Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The LUCI Authors. All rights reserved. | 1 // Copyright 2016 The LUCI Authors. All rights reserved. |
|
dnj
2017/01/06 18:51:41
You can probably not care about this. It's just a
| |
| 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 main implements a simple CLI tool to load and interact with storage | 5 // Package main implements a simple CLI tool to load and interact with storage |
| 6 // data in Google BigTable data. | 6 // data in Google BigTable data. |
| 7 package main | 7 package main |
| 8 | 8 |
| 9 import ( | 9 import ( |
| 10 "bytes" | 10 "bytes" |
| 11 "flag" | 11 "flag" |
| 12 "io" | 12 "io" |
| 13 "os" | 13 "os" |
| 14 | 14 |
| 15 "github.com/luci/luci-go/client/authcli" | 15 "github.com/luci/luci-go/client/authcli" |
| 16 "github.com/luci/luci-go/common/auth" | 16 "github.com/luci/luci-go/common/auth" |
| 17 "github.com/luci/luci-go/common/cli" | 17 "github.com/luci/luci-go/common/cli" |
| 18 "github.com/luci/luci-go/common/config" | 18 "github.com/luci/luci-go/common/config" |
| 19 "github.com/luci/luci-go/common/errors" | 19 "github.com/luci/luci-go/common/errors" |
| 20 log "github.com/luci/luci-go/common/logging" | 20 log "github.com/luci/luci-go/common/logging" |
| 21 "github.com/luci/luci-go/common/logging/gologger" | 21 "github.com/luci/luci-go/common/logging/gologger" |
| 22 "github.com/luci/luci-go/logdog/common/storage" | 22 "github.com/luci/luci-go/logdog/common/storage" |
| 23 "github.com/luci/luci-go/logdog/common/storage/bigtable" | 23 "github.com/luci/luci-go/logdog/common/storage/bigtable" |
| 24 "github.com/luci/luci-go/logdog/common/storage/memory" | |
| 24 "github.com/luci/luci-go/logdog/common/types" | 25 "github.com/luci/luci-go/logdog/common/types" |
| 25 | 26 |
| 26 "github.com/golang/protobuf/proto" | 27 "github.com/golang/protobuf/proto" |
| 27 "github.com/maruel/subcommands" | 28 "github.com/maruel/subcommands" |
| 28 "golang.org/x/net/context" | 29 "golang.org/x/net/context" |
| 29 "google.golang.org/api/option" | 30 "google.golang.org/api/option" |
| 30 ) | 31 ) |
| 31 | 32 |
| 32 //////////////////////////////////////////////////////////////////////////////// | 33 //////////////////////////////////////////////////////////////////////////////// |
| 33 // main | 34 // main |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 61 return nil, errors.Annotate(err).Reason("failed to get token sou rce").Err() | 62 return nil, errors.Annotate(err).Reason("failed to get token sou rce").Err() |
| 62 } | 63 } |
| 63 | 64 |
| 64 return bigtable.New(c, bigtable.Options{ | 65 return bigtable.New(c, bigtable.Options{ |
| 65 Project: app.btProject, | 66 Project: app.btProject, |
| 66 Instance: app.btInstance, | 67 Instance: app.btInstance, |
| 67 LogTable: app.btLogTable, | 68 LogTable: app.btLogTable, |
| 68 ClientOptions: []option.ClientOption{ | 69 ClientOptions: []option.ClientOption{ |
| 69 option.WithTokenSource(tsrc), | 70 option.WithTokenSource(tsrc), |
| 70 }, | 71 }, |
| 72 Cache: &memory.Cache{}, | |
| 71 }) | 73 }) |
| 72 } | 74 } |
| 73 | 75 |
| 74 func mainImpl(c context.Context, args []string) int { | 76 func mainImpl(c context.Context, args []string) int { |
| 75 c = gologger.StdConfig.Use(c) | 77 c = gologger.StdConfig.Use(c) |
| 76 | 78 |
| 77 logConfig := log.Config{ | 79 logConfig := log.Config{ |
| 78 Level: log.Warning, | 80 Level: log.Warning, |
| 79 } | 81 } |
| 80 | 82 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 168 //////////////////////////////////////////////////////////////////////////////// | 170 //////////////////////////////////////////////////////////////////////////////// |
| 169 // Subcommand: get | 171 // Subcommand: get |
| 170 //////////////////////////////////////////////////////////////////////////////// | 172 //////////////////////////////////////////////////////////////////////////////// |
| 171 | 173 |
| 172 type cmdRunGet struct { | 174 type cmdRunGet struct { |
| 173 subcommands.CommandRunBase | 175 subcommands.CommandRunBase |
| 174 | 176 |
| 175 project string | 177 project string |
| 176 path string | 178 path string |
| 177 | 179 |
| 178 » index int | 180 » index int |
| 179 » limit int | 181 » limit int |
| 182 » rounds int | |
| 180 } | 183 } |
| 181 | 184 |
| 182 var subcommandGet = subcommands.Command{ | 185 var subcommandGet = subcommands.Command{ |
| 183 UsageLine: "get", | 186 UsageLine: "get", |
| 184 ShortDesc: "Performs a Storage Get operation.", | 187 ShortDesc: "Performs a Storage Get operation.", |
| 185 CommandRun: func() subcommands.CommandRun { | 188 CommandRun: func() subcommands.CommandRun { |
| 186 var cmd cmdRunGet | 189 var cmd cmdRunGet |
| 187 | 190 |
| 188 cmd.Flags.StringVar(&cmd.project, "project", "", "Log stream pro ject name.") | 191 cmd.Flags.StringVar(&cmd.project, "project", "", "Log stream pro ject name.") |
| 189 cmd.Flags.StringVar(&cmd.path, "path", "", "Log stream path.") | 192 cmd.Flags.StringVar(&cmd.path, "path", "", "Log stream path.") |
| 190 cmd.Flags.IntVar(&cmd.index, "index", 0, "The index to fetch.") | 193 cmd.Flags.IntVar(&cmd.index, "index", 0, "The index to fetch.") |
| 191 cmd.Flags.IntVar(&cmd.limit, "limit", 0, "The log entry limit.") | 194 cmd.Flags.IntVar(&cmd.limit, "limit", 0, "The log entry limit.") |
| 195 cmd.Flags.IntVar(&cmd.rounds, "rounds", 1, "Number of rounds to run.") | |
| 192 | 196 |
| 193 return &cmd | 197 return &cmd |
| 194 }, | 198 }, |
| 195 } | 199 } |
| 196 | 200 |
| 197 func (cmd *cmdRunGet) Run(baseApp subcommands.Application, args []string, _ subc ommands.Env) int { | 201 func (cmd *cmdRunGet) Run(baseApp subcommands.Application, args []string, _ subc ommands.Env) int { |
| 198 app, c := getApplication(baseApp) | 202 app, c := getApplication(baseApp) |
| 199 | 203 |
| 200 switch { | 204 switch { |
| 201 case cmd.project == "": | 205 case cmd.project == "": |
| 202 log.Errorf(c, "Missing required argument (-project).") | 206 log.Errorf(c, "Missing required argument (-project).") |
| 203 return 1 | 207 return 1 |
| 204 case cmd.path == "": | 208 case cmd.path == "": |
| 205 log.Errorf(c, "Missing required argument (-path).") | 209 log.Errorf(c, "Missing required argument (-path).") |
| 206 return 1 | 210 return 1 |
| 207 } | 211 } |
| 208 | 212 |
| 209 stClient, err := app.getBigTableClient(c) | 213 stClient, err := app.getBigTableClient(c) |
| 210 if err != nil { | 214 if err != nil { |
| 211 renderErr(c, errors.Annotate(err).Reason("failed to create stora ge client").Err()) | 215 renderErr(c, errors.Annotate(err).Reason("failed to create stora ge client").Err()) |
| 212 return 1 | 216 return 1 |
| 213 } | 217 } |
| 214 defer stClient.Close() | 218 defer stClient.Close() |
| 215 | 219 |
| 216 » var innerErr error | 220 » for round := 0; round < cmd.rounds; round++ { |
| 217 » err = stClient.Get(storage.GetRequest{ | 221 » » log.Infof(c, "Get round %d.", round+1) |
| 218 » » Project: config.ProjectName(cmd.project), | 222 |
| 219 » » Path: types.StreamPath(cmd.path), | 223 » » var innerErr error |
| 220 » » Index: types.MessageIndex(cmd.index), | 224 » » err = stClient.Get(storage.GetRequest{ |
| 221 » » Limit: cmd.limit, | 225 » » » Project: config.ProjectName(cmd.project), |
| 222 » }, func(e *storage.Entry) bool { | 226 » » » Path: types.StreamPath(cmd.path), |
| 223 » » le, err := e.GetLogEntry() | 227 » » » Index: types.MessageIndex(cmd.index), |
| 224 » » if err != nil { | 228 » » » Limit: cmd.limit, |
| 225 » » » log.WithError(err).Errorf(c, "Failed to unmarshal log en try.") | 229 » » }, func(e *storage.Entry) bool { |
| 226 » » » return false | 230 » » » le, err := e.GetLogEntry() |
| 231 » » » if err != nil { | |
| 232 » » » » log.WithError(err).Errorf(c, "Failed to unmarsha l log entry.") | |
| 233 » » » » return false | |
| 234 » » » } | |
| 235 | |
| 236 » » » log.Fields{ | |
| 237 » » » » "index": le.StreamIndex, | |
| 238 » » » }.Infof(c, "Fetched log entry.") | |
| 239 | |
| 240 » » » if innerErr = unmarshalAndDump(c, os.Stdout, nil, le); i nnerErr != nil { | |
| 241 » » » » return false | |
| 242 » » » } | |
| 243 » » » return true | |
| 244 » » }) | |
| 245 » » switch { | |
| 246 » » case innerErr != nil: | |
| 247 » » » renderErr(c, errors.Annotate(err).Reason("failed to proc ess fetched log entries").Err()) | |
| 248 » » » return 1 | |
| 249 | |
| 250 » » case err != nil: | |
| 251 » » » renderErr(c, errors.Annotate(err).Reason("Failed to Get log entries.").Err()) | |
| 252 » » » return 1 | |
| 227 } | 253 } |
| 254 } | |
| 228 | 255 |
| 229 » » log.Fields{ | 256 » return 0 |
| 230 » » » "index": le.StreamIndex, | |
| 231 » » }.Infof(c, "Fetched log entry.") | |
| 232 | |
| 233 » » if innerErr = unmarshalAndDump(c, os.Stdout, nil, le); innerErr != nil { | |
| 234 » » » return false | |
| 235 » » } | |
| 236 » » return true | |
| 237 » }) | |
| 238 » switch { | |
| 239 » case innerErr != nil: | |
| 240 » » renderErr(c, errors.Annotate(err).Reason("failed to process fetc hed log entries").Err()) | |
| 241 » » return 1 | |
| 242 | |
| 243 » case err != nil: | |
| 244 » » renderErr(c, errors.Annotate(err).Reason("Failed to Get log entr ies.").Err()) | |
| 245 » » return 1 | |
| 246 | |
| 247 » default: | |
| 248 » » return 0 | |
| 249 » } | |
| 250 } | 257 } |
| 251 | 258 |
| 252 //////////////////////////////////////////////////////////////////////////////// | 259 //////////////////////////////////////////////////////////////////////////////// |
| 253 // Subcommand: tail | 260 // Subcommand: tail |
| 254 //////////////////////////////////////////////////////////////////////////////// | 261 //////////////////////////////////////////////////////////////////////////////// |
| 255 | 262 |
| 256 type cmdRunTail struct { | 263 type cmdRunTail struct { |
| 257 subcommands.CommandRunBase | 264 subcommands.CommandRunBase |
| 258 | 265 |
| 259 project string | 266 project string |
| 260 path string | 267 path string |
| 268 rounds int | |
| 261 } | 269 } |
| 262 | 270 |
| 263 var subcommandTail = subcommands.Command{ | 271 var subcommandTail = subcommands.Command{ |
| 264 UsageLine: "tail", | 272 UsageLine: "tail", |
| 265 ShortDesc: "Performs a Storage Tail operation.", | 273 ShortDesc: "Performs a Storage Tail operation.", |
| 266 CommandRun: func() subcommands.CommandRun { | 274 CommandRun: func() subcommands.CommandRun { |
| 267 var cmd cmdRunTail | 275 var cmd cmdRunTail |
| 268 | 276 |
| 269 cmd.Flags.StringVar(&cmd.project, "project", "", "Log stream pro ject name.") | 277 cmd.Flags.StringVar(&cmd.project, "project", "", "Log stream pro ject name.") |
| 270 cmd.Flags.StringVar(&cmd.path, "path", "", "Log stream path.") | 278 cmd.Flags.StringVar(&cmd.path, "path", "", "Log stream path.") |
| 279 cmd.Flags.IntVar(&cmd.rounds, "rounds", 1, "Number of rounds to run.") | |
| 271 | 280 |
| 272 return &cmd | 281 return &cmd |
| 273 }, | 282 }, |
| 274 } | 283 } |
| 275 | 284 |
| 276 func (cmd *cmdRunTail) Run(baseApp subcommands.Application, args []string, _ sub commands.Env) int { | 285 func (cmd *cmdRunTail) Run(baseApp subcommands.Application, args []string, _ sub commands.Env) int { |
| 277 app, c := getApplication(baseApp) | 286 app, c := getApplication(baseApp) |
| 278 | 287 |
| 279 switch { | 288 switch { |
| 280 case cmd.project == "": | 289 case cmd.project == "": |
| 281 log.Errorf(c, "Missing required argument (-project).") | 290 log.Errorf(c, "Missing required argument (-project).") |
| 282 return 1 | 291 return 1 |
| 283 case cmd.path == "": | 292 case cmd.path == "": |
| 284 log.Errorf(c, "Missing required argument (-path).") | 293 log.Errorf(c, "Missing required argument (-path).") |
| 285 return 1 | 294 return 1 |
| 286 } | 295 } |
| 287 | 296 |
| 288 stClient, err := app.getBigTableClient(c) | 297 stClient, err := app.getBigTableClient(c) |
| 289 if err != nil { | 298 if err != nil { |
| 290 renderErr(c, errors.Annotate(err).Reason("failed to create stora ge client").Err()) | 299 renderErr(c, errors.Annotate(err).Reason("failed to create stora ge client").Err()) |
| 291 return 1 | 300 return 1 |
| 292 } | 301 } |
| 293 defer stClient.Close() | 302 defer stClient.Close() |
| 294 | 303 |
| 295 » e, err := stClient.Tail(config.ProjectName(cmd.project), types.StreamPat h(cmd.path)) | 304 » for round := 0; round < cmd.rounds; round++ { |
| 296 » if err != nil { | 305 » » log.Infof(c, "Tail round %d.", round+1) |
| 297 » » renderErr(c, errors.Annotate(err).Reason("failed to tail log ent ries").Err()) | 306 » » e, err := stClient.Tail(config.ProjectName(cmd.project), types.S treamPath(cmd.path)) |
| 298 » » return 1 | 307 » » if err != nil { |
| 308 » » » renderErr(c, errors.Annotate(err).Reason("failed to tail log entries").Err()) | |
| 309 » » » return 1 | |
| 310 » » } | |
| 311 | |
| 312 » » if e == nil { | |
| 313 » » » log.Infof(c, "No log data to tail.") | |
| 314 » » » continue | |
| 315 » » } | |
| 316 | |
| 317 » » le, err := e.GetLogEntry() | |
| 318 » » if err != nil { | |
| 319 » » » renderErr(c, errors.Annotate(err).Reason("failed to unma rshal log entry").Err()) | |
| 320 » » » return 1 | |
| 321 » » } | |
| 322 | |
| 323 » » log.Fields{ | |
| 324 » » » "index": le.StreamIndex, | |
| 325 » » » "size": len(e.D), | |
| 326 » » }.Debugf(c, "Dumping tail entry.") | |
| 327 » » if err := unmarshalAndDump(c, os.Stdout, nil, le); err != nil { | |
| 328 » » » renderErr(c, errors.Annotate(err).Reason("failed to dump log entry").Err()) | |
| 329 » » » return 1 | |
| 330 » » } | |
| 299 } | 331 } |
| 300 | 332 |
| 301 if e == nil { | |
| 302 log.Infof(c, "No log data to tail.") | |
| 303 return 0 | |
| 304 } | |
| 305 | |
| 306 le, err := e.GetLogEntry() | |
| 307 if err != nil { | |
| 308 renderErr(c, errors.Annotate(err).Reason("failed to unmarshal lo g entry").Err()) | |
| 309 return 1 | |
| 310 } | |
| 311 | |
| 312 log.Fields{ | |
| 313 "index": le.StreamIndex, | |
| 314 "size": len(e.D), | |
| 315 }.Debugf(c, "Dumping tail entry.") | |
| 316 if err := unmarshalAndDump(c, os.Stdout, nil, le); err != nil { | |
| 317 renderErr(c, errors.Annotate(err).Reason("failed to dump log ent ry").Err()) | |
| 318 return 1 | |
| 319 } | |
| 320 return 0 | 333 return 0 |
| 321 } | 334 } |
| OLD | NEW |