-
Notifications
You must be signed in to change notification settings - Fork 76
Add new stats subcommands and improve historical stats #1678
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
99cd55a
fix(stats): return write errors from stats historical
jedisct1 afa3b4e
feat(stats): add --field flag to stats historical
jedisct1 70d74da
feat(stats): add stats aggregate subcommand
jedisct1 27cb8a0
feat(stats): add stats usage subcommand
jedisct1 8ed97ad
feat(stats): add stats domain-inspector subcommand
jedisct1 8358e81
feat(stats): add stats origin-inspector subcommand
jedisct1 05cb196
chore(stats): update root command description
jedisct1 3ec2e72
fix(stats): use API-provided hit_ratio
jedisct1 53e101a
Add // Optional comments
jedisct1 fc1ca30
Add link to the PR, for every changelog entry
jedisct1 bb8b513
Merge branch 'main' into fdenis/stats
jedisct1 c393319
Merge branch 'main' into fdenis/stats
jedisct1 efde3ad
Lint after golangci-lint update
jedisct1 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| package stats | ||
|
|
||
| import ( | ||
| "context" | ||
| "encoding/json" | ||
| "fmt" | ||
| "io" | ||
|
|
||
| "github.com/fastly/go-fastly/v13/fastly" | ||
|
|
||
| "github.com/fastly/cli/pkg/argparser" | ||
| "github.com/fastly/cli/pkg/global" | ||
| ) | ||
|
|
||
| // AggregateCommand exposes the Aggregate Stats API. | ||
| type AggregateCommand struct { | ||
| argparser.Base | ||
|
|
||
| by string | ||
|
jedisct1 marked this conversation as resolved.
|
||
| formatFlag string | ||
| from string | ||
| region string | ||
| to string | ||
| } | ||
|
|
||
| // NewAggregateCommand is the "stats aggregate" subcommand. | ||
| func NewAggregateCommand(parent argparser.Registerer, g *global.Data) *AggregateCommand { | ||
| var c AggregateCommand | ||
| c.Globals = g | ||
|
|
||
| c.CmdClause = parent.Command("aggregate", "View aggregated stats across all services") | ||
|
|
||
| // Optional. | ||
| c.CmdClause.Flag("from", "Start time").StringVar(&c.from) | ||
| c.CmdClause.Flag("to", "End time").StringVar(&c.to) | ||
| c.CmdClause.Flag("by", "Aggregation period (minute/hour/day)").EnumVar(&c.by, "minute", "hour", "day") | ||
| c.CmdClause.Flag("region", "Filter by region ('stats regions' to list)").StringVar(&c.region) | ||
| c.CmdClause.Flag("format", "Output format (json)").EnumVar(&c.formatFlag, "json") | ||
|
|
||
| return &c | ||
| } | ||
|
|
||
| // Exec implements the command interface. | ||
| func (c *AggregateCommand) Exec(_ io.Reader, out io.Writer) error { | ||
| input := fastly.GetAggregateInput{} | ||
| if c.by != "" { | ||
| input.By = &c.by | ||
| } | ||
| if c.from != "" { | ||
| input.From = &c.from | ||
| } | ||
| if c.region != "" { | ||
| input.Region = &c.region | ||
| } | ||
| if c.to != "" { | ||
| input.To = &c.to | ||
| } | ||
|
|
||
| var envelope statsResponse | ||
|
anthony-gomez-fastly marked this conversation as resolved.
|
||
| err := c.Globals.APIClient.GetAggregateJSON(context.TODO(), &input, &envelope) | ||
| if err != nil { | ||
| c.Globals.ErrLog.Add(err) | ||
| return err | ||
| } | ||
|
|
||
| if envelope.Status != statusSuccess { | ||
|
anthony-gomez-fastly marked this conversation as resolved.
|
||
| return fmt.Errorf("non-success response: %s", envelope.Msg) | ||
| } | ||
|
|
||
| switch c.formatFlag { | ||
| case "json": | ||
| for _, block := range envelope.Data { | ||
| if err := json.NewEncoder(out).Encode(block); err != nil { | ||
| c.Globals.ErrLog.Add(err) | ||
| return err | ||
| } | ||
| } | ||
| default: | ||
| writeHeader(out, envelope.Meta) | ||
| for _, block := range envelope.Data { | ||
| if err := fmtBlock(out, "aggregate", block); err != nil { | ||
| c.Globals.ErrLog.Add(err) | ||
| return err | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| package stats_test | ||
|
|
||
| import ( | ||
| "bytes" | ||
| "context" | ||
| "encoding/json" | ||
| "io" | ||
| "testing" | ||
|
|
||
| "github.com/fastly/go-fastly/v13/fastly" | ||
|
|
||
| "github.com/fastly/cli/pkg/app" | ||
| "github.com/fastly/cli/pkg/global" | ||
| "github.com/fastly/cli/pkg/mock" | ||
| "github.com/fastly/cli/pkg/testutil" | ||
| ) | ||
|
|
||
| func TestAggregate(t *testing.T) { | ||
| args := testutil.SplitArgs | ||
| scenarios := []struct { | ||
| name string | ||
| args []string | ||
| api mock.API | ||
| wantError string | ||
| wantOutput string | ||
| }{ | ||
| { | ||
| name: "success table", | ||
| args: args("stats aggregate"), | ||
| api: mock.API{GetAggregateJSONFn: getAggregateJSONOK}, | ||
| wantOutput: "From:", | ||
| }, | ||
| { | ||
| name: "success json", | ||
| args: args("stats aggregate --format=json"), | ||
| api: mock.API{GetAggregateJSONFn: getAggregateJSONOK}, | ||
| wantOutput: `"start_time":0`, | ||
| }, | ||
| { | ||
| name: "non-success status", | ||
| args: args("stats aggregate"), | ||
| api: mock.API{GetAggregateJSONFn: getAggregateJSONNonSuccess}, | ||
| wantError: "non-success response", | ||
| }, | ||
| { | ||
| name: "api error", | ||
| args: args("stats aggregate"), | ||
| api: mock.API{GetAggregateJSONFn: getAggregateJSONError}, | ||
| wantError: errTest.Error(), | ||
| }, | ||
| } | ||
| for _, tc := range scenarios { | ||
| t.Run(tc.name, func(t *testing.T) { | ||
| var stdout bytes.Buffer | ||
| app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { | ||
| opts := testutil.MockGlobalData(tc.args, &stdout) | ||
| opts.APIClientFactory = mock.APIClient(tc.api) | ||
| return opts, nil | ||
| } | ||
| err := app.Run(tc.args, nil) | ||
| testutil.AssertErrorContains(t, err, tc.wantError) | ||
| testutil.AssertStringContains(t, stdout.String(), tc.wantOutput) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func getAggregateJSONOK(_ context.Context, _ *fastly.GetAggregateInput, o any) error { | ||
| msg := []byte(`{ | ||
| "status": "success", | ||
| "meta": {"to": "Thu May 16 20:08:35 UTC 2013", "from": "Wed May 15 20:08:35 UTC 2013", "by": "day", "region": "all"}, | ||
| "msg": null, | ||
| "data": [{"start_time": 0}] | ||
| }`) | ||
| return json.Unmarshal(msg, o) | ||
| } | ||
|
|
||
| func getAggregateJSONNonSuccess(_ context.Context, _ *fastly.GetAggregateInput, o any) error { | ||
| msg := []byte(`{"status": "error", "msg": "bad request", "meta": {}, "data": []}`) | ||
| return json.Unmarshal(msg, o) | ||
| } | ||
|
|
||
| func getAggregateJSONError(_ context.Context, _ *fastly.GetAggregateInput, _ any) error { | ||
| return errTest | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.