| OLD | NEW |
| 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 "errors" |
| 8 "fmt" | 9 "fmt" |
| 9 "net/http" | |
| 10 "time" | 10 "time" |
| 11 | 11 |
| 12 log "github.com/luci/luci-go/common/logging" | 12 log "github.com/luci/luci-go/common/logging" |
| 13 "github.com/luci/luci-go/common/proto/google" | 13 "github.com/luci/luci-go/common/proto/google" |
| 14 miloProto "github.com/luci/luci-go/common/proto/milo" | 14 miloProto "github.com/luci/luci-go/common/proto/milo" |
| 15 "github.com/luci/luci-go/logdog/api/logpb" | 15 "github.com/luci/luci-go/logdog/api/logpb" |
| 16 "github.com/luci/luci-go/logdog/client/coordinator" | 16 "github.com/luci/luci-go/logdog/client/coordinator" |
| 17 "github.com/luci/luci-go/logdog/common/types" | 17 "github.com/luci/luci-go/logdog/common/types" |
| 18 "github.com/luci/luci-go/logdog/common/viewer" | 18 "github.com/luci/luci-go/logdog/common/viewer" |
| 19 "github.com/luci/luci-go/luci_config/common/cfgtypes" | 19 "github.com/luci/luci-go/luci_config/common/cfgtypes" |
| 20 "github.com/luci/luci-go/milo/api/resp" | 20 "github.com/luci/luci-go/milo/api/resp" |
| 21 "github.com/luci/luci-go/milo/appengine/logdog/internal" | 21 "github.com/luci/luci-go/milo/appengine/logdog/internal" |
| 22 "github.com/luci/luci-go/milo/common/miloerror" | |
| 23 | 22 |
| 24 "github.com/golang/protobuf/proto" | 23 "github.com/golang/protobuf/proto" |
| 25 "golang.org/x/net/context" | 24 "golang.org/x/net/context" |
| 26 ) | 25 ) |
| 27 | 26 |
| 28 const ( | 27 const ( |
| 29 // intermediateCacheLifetime is the amount of time to cache intermediate
(non- | 28 // intermediateCacheLifetime is the amount of time to cache intermediate
(non- |
| 30 // terminal) annotation streams. Terminal annotation streams are cached | 29 // terminal) annotation streams. Terminal annotation streams are cached |
| 31 // indefinitely. | 30 // indefinitely. |
| 32 intermediateCacheLifetime = 10 * time.Second | 31 intermediateCacheLifetime = 10 * time.Second |
| (...skipping 21 matching lines...) Expand all Loading... |
| 54 return fmt.Errorf("Invalid project name: %s", as.Project) | 53 return fmt.Errorf("Invalid project name: %s", as.Project) |
| 55 } | 54 } |
| 56 | 55 |
| 57 if err := as.Path.Validate(); err != nil { | 56 if err := as.Path.Validate(); err != nil { |
| 58 return fmt.Errorf("Invalid log stream path %q: %s", as.Path, err
) | 57 return fmt.Errorf("Invalid log stream path %q: %s", as.Path, err
) |
| 59 } | 58 } |
| 60 | 59 |
| 61 return nil | 60 return nil |
| 62 } | 61 } |
| 63 | 62 |
| 63 var errNotMilo = errors.New("Requested stream is not a Milo annotation protobuf"
) |
| 64 var errNotDatagram = errors.New("Requested stream is not a datagram stream") |
| 65 var errNoEntries = errors.New("Log stream has no annotation entries") |
| 66 |
| 64 // Fetch loads the annotation stream from LogDog. | 67 // Fetch loads the annotation stream from LogDog. |
| 65 // | 68 // |
| 66 // If the stream does not exist, or is invalid, Fetch will return a Milo error. | 69 // If the stream does not exist, or is invalid, Fetch will return a Milo error. |
| 67 // Otherwise, it will return the Step that was loaded. | 70 // Otherwise, it will return the Step that was loaded. |
| 68 // | 71 // |
| 69 // Fetch caches the step, so multiple calls to Fetch will return the same Step | 72 // Fetch caches the step, so multiple calls to Fetch will return the same Step |
| 70 // value. | 73 // value. |
| 71 func (as *AnnotationStream) Fetch(c context.Context) (*miloProto.Step, error) { | 74 func (as *AnnotationStream) Fetch(c context.Context) (*miloProto.Step, error) { |
| 72 // Cached? | 75 // Cached? |
| 73 if as.cs.Step != nil { | 76 if as.cs.Step != nil { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 88 | 91 |
| 89 le, err := stream.Tail(c, coordinator.WithState(&state), coordinator.Com
plete()) | 92 le, err := stream.Tail(c, coordinator.WithState(&state), coordinator.Com
plete()) |
| 90 if err != nil { | 93 if err != nil { |
| 91 log.WithError(err).Errorf(c, "Failed to load stream.") | 94 log.WithError(err).Errorf(c, "Failed to load stream.") |
| 92 return nil, err | 95 return nil, err |
| 93 } | 96 } |
| 94 | 97 |
| 95 // Make sure that this is an annotation stream. | 98 // Make sure that this is an annotation stream. |
| 96 switch { | 99 switch { |
| 97 case state.Desc.ContentType != miloProto.ContentTypeAnnotations: | 100 case state.Desc.ContentType != miloProto.ContentTypeAnnotations: |
| 98 » » return nil, &miloerror.Error{ | 101 » » return nil, errNotMilo |
| 99 » » » Message: "Requested stream is not a Milo annotation prot
obuf", | |
| 100 » » » Code: http.StatusBadRequest, | |
| 101 » » } | |
| 102 | 102 |
| 103 case state.Desc.StreamType != logpb.StreamType_DATAGRAM: | 103 case state.Desc.StreamType != logpb.StreamType_DATAGRAM: |
| 104 » » return nil, &miloerror.Error{ | 104 » » return nil, errNotDatagram |
| 105 » » » Message: "Requested stream is not a datagram stream", | |
| 106 » » » Code: http.StatusBadRequest, | |
| 107 » » } | |
| 108 | 105 |
| 109 case le == nil: | 106 case le == nil: |
| 110 // No annotation stream data, so render a minimal page. | 107 // No annotation stream data, so render a minimal page. |
| 111 » » return nil, &miloerror.Error{ | 108 » » return nil, errNoEntries |
| 112 » » » Message: "Log stream has no annotation entries", | |
| 113 » » » Code: http.StatusNotFound, | |
| 114 » » } | |
| 115 } | 109 } |
| 116 | 110 |
| 117 // Get the last log entry in the stream. In reality, this will be index
0, | 111 // Get the last log entry in the stream. In reality, this will be index
0, |
| 118 // since the "Tail" call should only return one log entry. | 112 // since the "Tail" call should only return one log entry. |
| 119 // | 113 // |
| 120 // Because we supplied the "Complete" flag to Tail and suceeded, this da
tagram | 114 // Because we supplied the "Complete" flag to Tail and suceeded, this da
tagram |
| 121 // will be complete even if its source datagram(s) are fragments. | 115 // will be complete even if its source datagram(s) are fragments. |
| 122 dg := le.GetDatagram() | 116 dg := le.GetDatagram() |
| 123 if dg == nil { | 117 if dg == nil { |
| 124 » » return nil, &miloerror.Error{ | 118 » » return nil, errors.New("Datagram stream does not have datagram d
ata") |
| 125 » » » Message: "Datagram stream does not have datagram data", | |
| 126 » » » Code: http.StatusInternalServerError, | |
| 127 » » } | |
| 128 } | 119 } |
| 129 | 120 |
| 130 // Attempt to decode the Step protobuf. | 121 // Attempt to decode the Step protobuf. |
| 131 var step miloProto.Step | 122 var step miloProto.Step |
| 132 if err := proto.Unmarshal(dg.Data, &step); err != nil { | 123 if err := proto.Unmarshal(dg.Data, &step); err != nil { |
| 133 » » return nil, &miloerror.Error{ | 124 » » return nil, err |
| 134 » » » Message: "Failed to unmarshal annotation protobuf", | |
| 135 » » » Code: http.StatusInternalServerError, | |
| 136 » » } | |
| 137 } | 125 } |
| 138 | 126 |
| 139 var latestEndedTime time.Time | 127 var latestEndedTime time.Time |
| 140 for _, sub := range step.Substep { | 128 for _, sub := range step.Substep { |
| 141 switch t := sub.Substep.(type) { | 129 switch t := sub.Substep.(type) { |
| 142 case *miloProto.Step_Substep_AnnotationStream: | 130 case *miloProto.Step_Substep_AnnotationStream: |
| 143 // TODO(hinoka,dnj): Implement recursive / embedded subs
tream fetching if | 131 // TODO(hinoka,dnj): Implement recursive / embedded subs
tream fetching if |
| 144 // specified. | 132 // specified. |
| 145 log.Warningf(c, "Annotation stream links LogDog substrea
m [%+v], not supported!", t.AnnotationStream) | 133 log.Warningf(c, "Annotation stream links LogDog substrea
m [%+v], not supported!", t.AnnotationStream) |
| 146 | 134 |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 232 if link.Label == "" { | 220 if link.Label == "" { |
| 233 link.Label = "unnamed" | 221 link.Label = "unnamed" |
| 234 } | 222 } |
| 235 return &link | 223 return &link |
| 236 | 224 |
| 237 default: | 225 default: |
| 238 // Don't know how to render. | 226 // Don't know how to render. |
| 239 return nil | 227 return nil |
| 240 } | 228 } |
| 241 } | 229 } |
| OLD | NEW |