Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(51)

Side by Side Diff: milo/appengine/logdog/build.go

Issue 2695383002: milo: Enable Swarming LogDog log loading. (Closed)
Patch Set: Comments, fix links. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The LUCI Authors. All rights reserved. 1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be found in the LICENSE file.
4 4
5 package logdog 5 package logdog
6 6
7 import ( 7 import (
8 "fmt" 8 "fmt"
9 "net/http" 9 "net/http"
10 "time" 10 "time"
(...skipping 26 matching lines...) Expand all
37 // defaultLogDogHost is the default LogDog host, if one isn't specified via 37 // defaultLogDogHost is the default LogDog host, if one isn't specified via
38 // query string. 38 // query string.
39 defaultLogDogHost = "luci-logdog.appspot.com" 39 defaultLogDogHost = "luci-logdog.appspot.com"
40 ) 40 )
41 41
42 // AnnotationStream represents a LogDog annotation protobuf stream. 42 // AnnotationStream represents a LogDog annotation protobuf stream.
43 type AnnotationStream struct { 43 type AnnotationStream struct {
44 Project cfgtypes.ProjectName 44 Project cfgtypes.ProjectName
45 Path types.StreamPath 45 Path types.StreamPath
46 46
47 » // logDogClient is the HTTP client to use for LogDog communication. 47 » // Client is the HTTP client to use for LogDog communication.
48 Client *coordinator.Client 48 Client *coordinator.Client
49 49
50 // cs is the unmarshalled annotation stream Step and associated data. 50 // cs is the unmarshalled annotation stream Step and associated data.
51 cs internal.CachedStep 51 cs internal.CachedStep
52 } 52 }
53 53
54 // Normalize validates and normalizes the stream's parameters. 54 // Normalize validates and normalizes the stream's parameters.
55 func (as *AnnotationStream) Normalize() error { 55 func (as *AnnotationStream) Normalize() error {
56 if err := as.Project.Validate(); err != nil { 56 if err := as.Project.Validate(); err != nil {
57 return fmt.Errorf("Invalid project name: %s", as.Project) 57 return fmt.Errorf("Invalid project name: %s", as.Project)
58 } 58 }
59 59
60 if err := as.Path.Validate(); err != nil { 60 if err := as.Path.Validate(); err != nil {
61 return fmt.Errorf("Invalid log stream path %q: %s", as.Path, err ) 61 return fmt.Errorf("Invalid log stream path %q: %s", as.Path, err )
62 } 62 }
63 63
64 return nil 64 return nil
65 } 65 }
66 66
67 // Load loads the annotation stream from LogDog. 67 // Fetch loads the annotation stream from LogDog.
68 // 68 //
69 // If the stream does not exist, or is invalid, Load will return a Milo error. 69 // If the stream does not exist, or is invalid, Fetch will return a Milo error.
70 // Otherwise, it will return the Step that was loaded. 70 // Otherwise, it will return the Step that was loaded.
71 // 71 //
72 // Load caches the step, so multiple calls to Load will return the same Step 72 // Fetch caches the step, so multiple calls to Fetch will return the same Step
73 // value. 73 // value.
74 func (as *AnnotationStream) Load(c context.Context) (*miloProto.Step, error) { 74 func (as *AnnotationStream) Fetch(c context.Context) (*miloProto.Step, error) {
75 // Cached? 75 // Cached?
76 if as.cs.Step != nil { 76 if as.cs.Step != nil {
77 return as.cs.Step, nil 77 return as.cs.Step, nil
78 } 78 }
79 79
80 // Load from memcache, if possible. If an error occurs, we will proceed as if 80 // Load from memcache, if possible. If an error occurs, we will proceed as if
81 // no CachedStep was available. 81 // no CachedStep was available.
82 mcKey := as.memcacheKey() 82 mcKey := as.memcacheKey()
83 mcItem, err := mc.GetKey(c, mcKey) 83 mcItem, err := mc.GetKey(c, mcKey)
84 switch err { 84 switch err {
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
205 // No substep had an ended time :( 205 // No substep had an ended time :(
206 latestEndedTime = google.TimeFromProto(step.Started) 206 latestEndedTime = google.TimeFromProto(step.Started)
207 } 207 }
208 208
209 // Build our CachedStep. 209 // Build our CachedStep.
210 as.cs = internal.CachedStep{ 210 as.cs = internal.CachedStep{
211 Step: &step, 211 Step: &step,
212 Finished: (state.State.TerminalIndex >= 0 && le.StreamIndex == u int64(state.State.TerminalIndex)), 212 Finished: (state.State.TerminalIndex >= 0 && le.StreamIndex == u int64(state.State.TerminalIndex)),
213 } 213 }
214 214
215 // Annotee is apparently not putting an ended time on some annotation pr otos.
216 // This hack will ensure that a finished build will always have an ended time.
217 if as.cs.Finished && as.cs.Step.Ended == nil {
218 as.cs.Step.Ended = google.NewTimestamp(latestEndedTime)
219 }
220
221 // Marshal and cache the step. If this is the final protobuf in the stre am, 215 // Marshal and cache the step. If this is the final protobuf in the stre am,
222 // cache it indefinitely; otherwise, cache it for intermediateCacheLifet ime. 216 // cache it indefinitely; otherwise, cache it for intermediateCacheLifet ime.
223 // 217 //
224 // If this fails, it is non-fatal. 218 // If this fails, it is non-fatal.
225 mcData, err := proto.Marshal(&as.cs) 219 mcData, err := proto.Marshal(&as.cs)
226 if err == nil { 220 if err == nil {
227 mcItem = mc.NewItem(c, mcKey) 221 mcItem = mc.NewItem(c, mcKey)
228 if !as.cs.Finished { 222 if !as.cs.Finished {
229 mcItem.SetExpiration(intermediateCacheLifetime) 223 mcItem.SetExpiration(intermediateCacheLifetime)
230 } 224 }
(...skipping 22 matching lines...) Expand all
253 Prefix: string(prefix), 247 Prefix: string(prefix),
254 Path: string(name), 248 Path: string(name),
255 IsDatagram: true, 249 IsDatagram: true,
256 Data: as.cs.Step, 250 Data: as.cs.Step,
257 Closed: as.cs.Finished, 251 Closed: as.cs.Finished,
258 }, 252 },
259 } 253 }
260 254
261 var ( 255 var (
262 build resp.MiloBuild 256 build resp.MiloBuild
263 » » ub = logDogURLBuilder{ 257 » » ub = ViewerURLBuilder{
264 » » » host: as.Client.Host, 258 » » » Host: as.Client.Host,
265 » » » project: as.Project, 259 » » » Project: as.Project,
266 » » » prefix: prefix, 260 » » » Prefix: prefix,
267 } 261 }
268 ) 262 )
269 AddLogDogToBuild(c, &ub, streams.MainStream.Data, &build) 263 AddLogDogToBuild(c, &ub, streams.MainStream.Data, &build)
270 return &build 264 return &build
271 } 265 }
272 266
273 type logDogURLBuilder struct { 267 // ViewerURLBuilder is a URL builder that constructs LogDog viewer URLs.
274 » host string 268 type ViewerURLBuilder struct {
275 » prefix types.StreamName 269 » Host string
276 » project cfgtypes.ProjectName 270 » Prefix types.StreamName
271 » Project cfgtypes.ProjectName
277 } 272 }
278 273
279 func (b *logDogURLBuilder) BuildLink(l *miloProto.Link) *resp.Link { 274 // BuildLink implements URLBuilder.
275 func (b *ViewerURLBuilder) BuildLink(l *miloProto.Link) *resp.Link {
280 switch t := l.Value.(type) { 276 switch t := l.Value.(type) {
281 case *miloProto.Link_LogdogStream: 277 case *miloProto.Link_LogdogStream:
282 ls := t.LogdogStream 278 ls := t.LogdogStream
283 279
284 server := ls.Server 280 server := ls.Server
285 if server == "" { 281 if server == "" {
286 » » » server = b.host 282 » » » server = b.Host
287 } 283 }
288 284
289 prefix := types.StreamName(ls.Prefix) 285 prefix := types.StreamName(ls.Prefix)
290 if prefix == "" { 286 if prefix == "" {
291 » » » prefix = b.prefix 287 » » » prefix = b.Prefix
292 } 288 }
293 289
294 » » u := viewer.GetURL(server, b.project, prefix.Join(types.StreamNa me(ls.Name))) 290 » » u := viewer.GetURL(server, b.Project, prefix.Join(types.StreamNa me(ls.Name)))
295 link := resp.Link{ 291 link := resp.Link{
296 Label: l.Label, 292 Label: l.Label,
297 URL: u, 293 URL: u,
298 } 294 }
299 if link.Label == "" { 295 if link.Label == "" {
300 link.Label = ls.Name 296 link.Label = ls.Name
301 } 297 }
302 return &link 298 return &link
303 299
304 case *miloProto.Link_Url: 300 case *miloProto.Link_Url:
305 link := resp.Link{ 301 link := resp.Link{
306 Label: l.Label, 302 Label: l.Label,
307 URL: t.Url, 303 URL: t.Url,
308 } 304 }
309 if link.Label == "" { 305 if link.Label == "" {
310 link.Label = "unnamed" 306 link.Label = "unnamed"
311 } 307 }
312 return &link 308 return &link
313 309
314 default: 310 default:
315 // Don't know how to render. 311 // Don't know how to render.
316 return nil 312 return nil
317 } 313 }
318 } 314 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698