Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Dispatcher usage: | 5 // Dispatcher usage: |
| 6 // go run infra/monitoring/dispatcher | 6 // go run infra/monitoring/dispatcher |
| 7 // Expects gatekeeper.json to be in the current directory. | 7 // Expects gatekeeper.json to be in the current directory. |
| 8 | 8 |
| 9 package main | 9 package main |
| 10 | 10 |
| 11 import ( | 11 import ( |
| 12 "encoding/json" | 12 "encoding/json" |
| 13 "expvar" | 13 "expvar" |
| 14 "flag" | 14 "flag" |
| 15 "fmt" | 15 "fmt" |
| 16 "io/ioutil" | 16 "io/ioutil" |
| 17 "log" | 17 "log" |
| 18 "net" | 18 "net" |
| 19 "net/http" | 19 "net/http" |
| 20 "net/url" | 20 "net/url" |
| 21 "os" | 21 "os" |
| 22 "sort" | 22 "sort" |
| 23 "strings" | 23 "strings" |
| 24 "time" | 24 "time" |
| 25 | 25 |
| 26 "github.com/luci/luci-go/common/auth" | 26 "github.com/luci/luci-go/common/auth" |
| 27 "github.com/luci/luci-go/common/clock" | 27 "github.com/luci/luci-go/common/clock" |
| 28 "github.com/luci/luci-go/common/logging" | 28 "github.com/luci/luci-go/common/logging" |
| 29 "github.com/luci/luci-go/common/logging/gologger" | 29 "github.com/luci/luci-go/common/logging/gologger" |
| 30 "github.com/luci/luci-go/common/tsmon" | |
| 31 "github.com/luci/luci-go/common/tsmon/field" | |
| 32 "github.com/luci/luci-go/common/tsmon/metric" | |
| 33 "github.com/luci/luci-go/common/tsmon/types" | |
| 30 | 34 |
| 31 "golang.org/x/net/context" | 35 "golang.org/x/net/context" |
| 32 | 36 |
| 33 "infra/monitoring/analyzer" | 37 "infra/monitoring/analyzer" |
| 34 "infra/monitoring/client" | 38 "infra/monitoring/client" |
| 35 "infra/monitoring/looper" | 39 "infra/monitoring/looper" |
| 36 "infra/monitoring/messages" | 40 "infra/monitoring/messages" |
| 37 ) | 41 ) |
| 38 | 42 |
| 39 type stringSlice []string | 43 type stringSlice []string |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 69 duration, cycle time.Duration | 73 duration, cycle time.Duration |
| 70 | 74 |
| 71 // gk is the gatekeeper config. | 75 // gk is the gatekeeper config. |
| 72 gks = []*messages.GatekeeperConfig{} | 76 gks = []*messages.GatekeeperConfig{} |
| 73 // gkt is the gatekeeper trees config. | 77 // gkt is the gatekeeper trees config. |
| 74 gkts = map[string][]messages.TreeMasterConfig{} | 78 gkts = map[string][]messages.TreeMasterConfig{} |
| 75 filteredFailures = uint64(0) | 79 filteredFailures = uint64(0) |
| 76 expvars = expvar.NewMap("dispatcher") | 80 expvars = expvar.NewMap("dispatcher") |
| 77 errLog = log.New(os.Stderr, "", log.Lshortfile|log.Ltime) | 81 errLog = log.New(os.Stderr, "", log.Lshortfile|log.Ltime) |
| 78 infoLog = log.New(os.Stdout, "", log.Lshortfile|log.Ltime) | 82 infoLog = log.New(os.Stdout, "", log.Lshortfile|log.Ltime) |
| 83 | |
| 84 // tsmon metrics | |
| 85 iterations = metric.NewCounter("alerts_dispatcher/iterations", | |
| 86 "Number if iterations of the main polling loop.", types.MetricMe tadata{}, field.String("status")) | |
| 87 postErrors = metric.NewCounter("alerts_dispatcher/post_errors", | |
| 88 "Number of posting errors.", types.MetricMetadata{}) | |
| 89 alertCount = metric.NewInt("alerts_dispatcher/alert_count", | |
| 90 "Number of alerts generated.", types.MetricMetadata{}, | |
| 91 field.String("tree")) | |
| 79 ) | 92 ) |
| 80 | 93 |
| 81 func init() { | 94 func init() { |
| 82 flag.Usage = func() { | 95 flag.Usage = func() { |
| 83 fmt.Printf("By default runs a single check, saves any alerts to ./alerts.json and exits.") | 96 fmt.Printf("By default runs a single check, saves any alerts to ./alerts.json and exits.") |
| 84 flag.PrintDefaults() | 97 flag.PrintDefaults() |
| 85 } | 98 } |
| 86 } | 99 } |
| 87 | 100 |
| 88 func analyzeBuildExtract(ctx context.Context, a *analyzer.Analyzer, tree string, masterURL *messages.MasterLocation, b *messages.BuildExtract) []messages.Alert { | 101 func analyzeBuildExtract(ctx context.Context, a *analyzer.Analyzer, tree string, masterURL *messages.MasterLocation, b *messages.BuildExtract) []messages.Alert { |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 191 errLog.Printf("Couldn't get revision summaries: %v", err) | 204 errLog.Printf("Couldn't get revision summaries: %v", err) |
| 192 continue | 205 continue |
| 193 } | 206 } |
| 194 for _, rev := range revs { | 207 for _, rev := range revs { |
| 195 alerts.RevisionSummaries [rev.GitHash] = rev | 208 alerts.RevisionSummaries [rev.GitHash] = rev |
| 196 } | 209 } |
| 197 } | 210 } |
| 198 } | 211 } |
| 199 } | 212 } |
| 200 alerts.Timestamp = messages.TimeToEpochTime(time.Now()) | 213 alerts.Timestamp = messages.TimeToEpochTime(time.Now()) |
| 214 alertCount.Set(ctx, int64(len(alerts.Alerts)), tree) | |
| 201 | 215 |
| 202 if *alertsBaseURL == "" { | 216 if *alertsBaseURL == "" { |
| 203 infoLog.Printf("No data_url provided. Writing to %s-alerts.json", tree) | 217 infoLog.Printf("No data_url provided. Writing to %s-alerts.json", tree) |
| 204 | 218 |
| 205 abytes, err := json.MarshalIndent(alerts, "", "\ t") | 219 abytes, err := json.MarshalIndent(alerts, "", "\ t") |
| 206 if err != nil { | 220 if err != nil { |
| 207 errLog.Printf("Couldn't marshal alerts j son: %v", err) | 221 errLog.Printf("Couldn't marshal alerts j son: %v", err) |
| 208 errs <- err | 222 errs <- err |
| 209 return | 223 return |
| 210 } | 224 } |
| 211 | 225 |
| 212 if err := ioutil.WriteFile(fmt.Sprintf("%s-alert s.json", tree), abytes, 0644); err != nil { | 226 if err := ioutil.WriteFile(fmt.Sprintf("%s-alert s.json", tree), abytes, 0644); err != nil { |
| 213 errLog.Printf("Couldn't write to alerts. json: %v", err) | 227 errLog.Printf("Couldn't write to alerts. json: %v", err) |
| 214 errs <- err | 228 errs <- err |
| 215 return | 229 return |
| 216 } | 230 } |
| 217 } else { | 231 } else { |
| 218 alertsURL := fmt.Sprintf("%s/%s", *alertsBaseURL , tree) | 232 alertsURL := fmt.Sprintf("%s/%s", *alertsBaseURL , tree) |
| 219 w := client.NewWriter(alertsURL, transport) | 233 w := client.NewWriter(alertsURL, transport) |
| 220 infoLog.Printf("Posting alerts to %s", alertsURL ) | 234 infoLog.Printf("Posting alerts to %s", alertsURL ) |
| 221 err := w.PostAlerts(alerts) | 235 err := w.PostAlerts(alerts) |
| 222 if err != nil { | 236 if err != nil { |
| 223 errLog.Printf("Couldn't post alerts: %v" , err) | 237 errLog.Printf("Couldn't post alerts: %v" , err) |
| 238 postErrors.Add(ctx, 1) | |
| 224 errs <- err | 239 errs <- err |
| 225 return | 240 return |
| 226 } | 241 } |
| 227 } | 242 } |
| 228 | 243 |
| 229 infoLog.Printf("Filtered failures: %v", filteredFailures ) | 244 infoLog.Printf("Filtered failures: %v", filteredFailures ) |
| 230 done <- nil | 245 done <- nil |
| 231 }() | 246 }() |
| 232 } | 247 } |
| 233 | 248 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 244 | 259 |
| 245 func main() { | 260 func main() { |
| 246 flag.Var(&gatekeeperJSON, "gatekeeper", "Location of gatekeeper json fil e. Can have multiple comma separated values.") | 261 flag.Var(&gatekeeperJSON, "gatekeeper", "Location of gatekeeper json fil e. Can have multiple comma separated values.") |
| 247 flag.Var(&gatekeeperTreesJSON, "gatekeeper-trees", "Location of gatekeep er tree json file. Can have multiple comma separated values.") | 262 flag.Var(&gatekeeperTreesJSON, "gatekeeper-trees", "Location of gatekeep er tree json file. Can have multiple comma separated values.") |
| 248 | 263 |
| 249 flag.Parse() | 264 flag.Parse() |
| 250 | 265 |
| 251 ctx := context.Background() | 266 ctx := context.Background() |
| 252 ctx = gologger.StdConfig.Use(ctx) | 267 ctx = gologger.StdConfig.Use(ctx) |
| 253 logging.SetLevel(ctx, logging.Debug) | 268 logging.SetLevel(ctx, logging.Debug) |
| 254 | |
| 255 authOptions := auth.Options{ | 269 authOptions := auth.Options{ |
| 256 ServiceAccountJSONPath: *serviceAccountJSON, | 270 ServiceAccountJSONPath: *serviceAccountJSON, |
| 257 Scopes: []string{ | 271 Scopes: []string{ |
| 258 auth.OAuthScopeEmail, | 272 auth.OAuthScopeEmail, |
| 259 "https://www.googleapis.com/auth/projecthosting", | 273 "https://www.googleapis.com/auth/projecthosting", |
| 260 }, | 274 }, |
| 261 Method: auth.ServiceAccountMethod, | 275 Method: auth.ServiceAccountMethod, |
| 262 } | 276 } |
| 263 | 277 |
| 264 mode := auth.SilentLogin | 278 mode := auth.SilentLogin |
| 265 if *login { | 279 if *login { |
| 266 mode = auth.InteractiveLogin | 280 mode = auth.InteractiveLogin |
| 267 } | 281 } |
| 268 | 282 |
| 269 transport, err := auth.NewAuthenticator(ctx, mode, authOptions).Transpor t() | 283 transport, err := auth.NewAuthenticator(ctx, mode, authOptions).Transpor t() |
| 270 if err != nil { | 284 if err != nil { |
| 271 errLog.Printf("AuthenticatedTransport: %v", err) | 285 errLog.Printf("AuthenticatedTransport: %v", err) |
| 272 if !*login { | 286 if !*login { |
| 273 errLog.Printf("Consider re-running with -login") | 287 errLog.Printf("Consider re-running with -login") |
| 274 } | 288 } |
| 275 os.Exit(1) | 289 os.Exit(1) |
| 276 } | 290 } |
| 277 ctx = context.Background() | 291 ctx = context.Background() |
| 278 | 292 |
| 293 tsFlags := tsmon.NewFlags() | |
| 294 tsFlags.Target.TargetType = "task" | |
| 295 tsFlags.Target.TaskServiceName = "alerts-dispatcher" | |
| 296 tsFlags.Flush = "auto" | |
| 297 tsmon.InitializeFromFlags(ctx, &tsFlags) | |
| 298 | |
| 279 // Start serving expvars. | 299 // Start serving expvars. |
| 280 go func() { | 300 go func() { |
| 281 listener, err := net.Listen("tcp", "127.0.0.1:0") | 301 listener, err := net.Listen("tcp", "127.0.0.1:0") |
| 282 if err != nil { | 302 if err != nil { |
| 283 errLog.Printf("Listen: %s", err) | 303 errLog.Printf("Listen: %s", err) |
| 284 os.Exit(1) | 304 os.Exit(1) |
| 285 } | 305 } |
| 286 | 306 |
| 287 infoLog.Printf("expvars listening on %v", listener.Addr()) | 307 infoLog.Printf("expvars listening on %v", listener.Addr()) |
| 288 | 308 |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 397 for tree := range trees { | 417 for tree := range trees { |
| 398 if _, ok := gkts[tree]; !ok { | 418 if _, ok := gkts[tree]; !ok { |
| 399 errLog.Printf("Unrecognized tree name: %s", tree) | 419 errLog.Printf("Unrecognized tree name: %s", tree) |
| 400 os.Exit(1) | 420 os.Exit(1) |
| 401 } | 421 } |
| 402 } | 422 } |
| 403 | 423 |
| 404 // This is the polling/analysis/alert posting function, which will run i n a loop until | 424 // This is the polling/analysis/alert posting function, which will run i n a loop until |
| 405 // a timeout or max errors is reached. | 425 // a timeout or max errors is reached. |
| 406 f := func(ctx context.Context) error { | 426 f := func(ctx context.Context) error { |
| 407 » » return mainLoop(ctx, a, trees, transport) | 427 » » err := mainLoop(ctx, a, trees, transport) |
| 428 » » if err == nil { | |
| 429 » » » iterations.Add(ctx, 1, "success") | |
|
dsansome
2016/08/26 08:44:52
Why not do this in looper instead, and use the sam
seanmccullough1
2016/08/26 19:48:22
+1 for doing it in looper, Not sure about using th
| |
| 430 » » } else { | |
| 431 » » » iterations.Add(ctx, 1, "failure") | |
| 432 » » } | |
| 433 » » return err | |
| 408 } | 434 } |
| 409 | 435 |
| 410 ctx, cancel := context.WithTimeout(ctx, duration) | 436 ctx, cancel := context.WithTimeout(ctx, duration) |
| 411 defer cancel() | 437 defer cancel() |
| 412 | 438 |
| 413 loopResults := looper.Run(ctx, f, cycle, *maxErrs, clock.GetSystemClock( )) | 439 loopResults := looper.Run(ctx, f, cycle, *maxErrs, clock.GetSystemClock( )) |
| 414 | 440 |
| 441 tsmon.Shutdown(ctx) | |
| 442 | |
| 415 if !loopResults.Success { | 443 if !loopResults.Success { |
| 416 errLog.Printf("Failed to run loop, %v errors", loopResults.Errs) | 444 errLog.Printf("Failed to run loop, %v errors", loopResults.Errs) |
| 417 os.Exit(1) | 445 os.Exit(1) |
| 418 } | 446 } |
| 419 } | 447 } |
| OLD | NEW |