Skip to content

Commit cd5b9d0

Browse files
authored
Add blank lines between entries of the "stats usage" text output (#1683)
### Change summary Add blank lines between entries in `stats usage` text output to improve readability and parsability . Right now, entries are difficult to split. All Submissions: * [x] Have you followed the guidelines in our Contributing document? * [x] Have you checked to ensure there aren't other open [Pull Requests](https://github.com/fastly/cli/pulls) for the same update/change? ### Changes to Core Features: * [x] Have you written new tests for your core changes, as applicable? * [x] Have you successfully run tests with your changes locally? ### User Impact Purely cosmetic. `fastly stats usage` output is now easier to parse. ### Are there any considerations that need to be addressed for release? None. This is a formatting-only change with no functional impact, on a feature that hasn't been deployed to any version. yet.
1 parent ad62873 commit cd5b9d0

7 files changed

Lines changed: 174 additions & 127 deletions

File tree

pkg/commands/stats/domain_inspector.go

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -143,40 +143,9 @@ func (c *DomainInspectorCommand) Exec(_ io.Reader, out io.Writer) error {
143143
if fastly.ToValue(resp.Status) != statusSuccess {
144144
return fmt.Errorf("non-success response: %s", fastly.ToValue(resp.Status))
145145
}
146-
return writeDomainInspector(out, resp)
147-
}
148-
}
149-
150-
func writeDomainInspector(out io.Writer, resp *fastly.DomainInspector) error {
151-
if resp.Meta != nil {
152-
if resp.Meta.Start != nil {
153-
text.Output(out, "Start: %s", *resp.Meta.Start)
154-
}
155-
if resp.Meta.End != nil {
156-
text.Output(out, "End: %s", *resp.Meta.End)
157-
}
158-
fmt.Fprintln(out, "---")
159-
}
160-
for _, d := range resp.Data {
161-
if d.Dimensions != nil {
162-
for k, v := range d.Dimensions {
163-
text.Output(out, "%s: %s", k, fastly.ToValue(v))
164-
}
165-
}
166-
for _, v := range d.Values {
167-
if v.Timestamp != nil {
168-
text.Output(out, " Timestamp: %s", time.Unix(int64(*v.Timestamp), 0).UTC()) //nolint:gosec // timestamp won't overflow
169-
}
170-
text.Output(out, " Requests: %d", fastly.ToValue(v.Requests))
171-
text.Output(out, " Bandwidth: %d", fastly.ToValue(v.Bandwidth))
172-
text.Output(out, " Edge Requests: %d", fastly.ToValue(v.EdgeRequests))
173-
text.Output(out, " Edge Hit Ratio: %.4f", fastly.ToValue(v.EdgeHitRatio))
174-
}
175-
}
176-
if resp.Meta != nil && resp.Meta.NextCursor != nil {
177-
text.Output(out, "Next cursor: %s", *resp.Meta.NextCursor)
146+
text.PrintDomainInspectorTbl(out, resp)
147+
return nil
178148
}
179-
return nil
180149
}
181150

182151
func parseTime(s string) (time.Time, error) {

pkg/commands/stats/domain_inspector_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func TestDomainInspector(t *testing.T) {
3232
api: mock.API{
3333
GetDomainMetricsForServiceFn: getDomainMetricsOK,
3434
},
35-
wantOutput: "Requests:",
35+
wantOutput: "REQUESTS",
3636
},
3737
{
3838
name: "success json",
@@ -78,23 +78,23 @@ func TestDomainInspector(t *testing.T) {
7878
api: mock.API{
7979
GetDomainMetricsForServiceFn: getDomainMetricsAssertStart(time.Date(2024, 1, 15, 10, 0, 0, 0, time.UTC)),
8080
},
81-
wantOutput: "Requests:",
81+
wantOutput: "REQUESTS",
8282
},
8383
{
8484
name: "from Unix epoch maps to Start",
8585
args: args("stats domain-inspector --service-id 123 --from 1705312800"),
8686
api: mock.API{
8787
GetDomainMetricsForServiceFn: getDomainMetricsAssertStart(time.Unix(1705312800, 0)),
8888
},
89-
wantOutput: "Requests:",
89+
wantOutput: "REQUESTS",
9090
},
9191
{
9292
name: "to RFC3339 maps to End",
9393
args: args("stats domain-inspector --service-id 123 --to 2024-01-15T11:00:00Z"),
9494
api: mock.API{
9595
GetDomainMetricsForServiceFn: getDomainMetricsAssertEnd(time.Date(2024, 1, 15, 11, 0, 0, 0, time.UTC)),
9696
},
97-
wantOutput: "Requests:",
97+
wantOutput: "REQUESTS",
9898
},
9999
{
100100
name: "from invalid format error",

pkg/commands/stats/origin_inspector.go

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"encoding/json"
66
"fmt"
77
"io"
8-
"time"
98

109
"github.com/fastly/go-fastly/v13/fastly"
1110

@@ -142,38 +141,7 @@ func (c *OriginInspectorCommand) Exec(_ io.Reader, out io.Writer) error {
142141
if fastly.ToValue(resp.Status) != statusSuccess {
143142
return fmt.Errorf("non-success response: %s", fastly.ToValue(resp.Status))
144143
}
145-
return writeOriginInspector(out, resp)
146-
}
147-
}
148-
149-
func writeOriginInspector(out io.Writer, resp *fastly.OriginInspector) error {
150-
if resp.Meta != nil {
151-
if resp.Meta.Start != nil {
152-
text.Output(out, "Start: %s", *resp.Meta.Start)
153-
}
154-
if resp.Meta.End != nil {
155-
text.Output(out, "End: %s", *resp.Meta.End)
156-
}
157-
fmt.Fprintln(out, "---")
158-
}
159-
for _, d := range resp.Data {
160-
if d.Dimensions != nil {
161-
for k, v := range d.Dimensions {
162-
text.Output(out, "%s: %s", k, v)
163-
}
164-
}
165-
for _, v := range d.Values {
166-
if v.Timestamp != nil {
167-
text.Output(out, " Timestamp: %s", time.Unix(int64(*v.Timestamp), 0).UTC()) //nolint:gosec // timestamp won't overflow
168-
}
169-
text.Output(out, " Responses: %d", fastly.ToValue(v.Responses))
170-
text.Output(out, " Status 2xx: %d", fastly.ToValue(v.Status2xx))
171-
text.Output(out, " Status 4xx: %d", fastly.ToValue(v.Status4xx))
172-
text.Output(out, " Status 5xx: %d", fastly.ToValue(v.Status5xx))
173-
}
174-
}
175-
if resp.Meta != nil && resp.Meta.NextCursor != nil {
176-
text.Output(out, "Next cursor: %s", *resp.Meta.NextCursor)
144+
text.PrintOriginInspectorTbl(out, resp)
145+
return nil
177146
}
178-
return nil
179147
}

pkg/commands/stats/origin_inspector_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func TestOriginInspector(t *testing.T) {
3232
api: mock.API{
3333
GetOriginMetricsForServiceFn: getOriginMetricsOK,
3434
},
35-
wantOutput: "Responses:",
35+
wantOutput: "RESPONSES",
3636
},
3737
{
3838
name: "success json",
@@ -78,23 +78,23 @@ func TestOriginInspector(t *testing.T) {
7878
api: mock.API{
7979
GetOriginMetricsForServiceFn: getOriginMetricsAssertStart(time.Date(2024, 1, 15, 10, 0, 0, 0, time.UTC)),
8080
},
81-
wantOutput: "Responses:",
81+
wantOutput: "RESPONSES",
8282
},
8383
{
8484
name: "from Unix epoch maps to Start",
8585
args: args("stats origin-inspector --service-id 123 --from 1705312800"),
8686
api: mock.API{
8787
GetOriginMetricsForServiceFn: getOriginMetricsAssertStart(time.Unix(1705312800, 0)),
8888
},
89-
wantOutput: "Responses:",
89+
wantOutput: "RESPONSES",
9090
},
9191
{
9292
name: "to RFC3339 maps to End",
9393
args: args("stats origin-inspector --service-id 123 --to 2024-01-15T11:00:00Z"),
9494
api: mock.API{
9595
GetOriginMetricsForServiceFn: getOriginMetricsAssertEnd(time.Date(2024, 1, 15, 11, 0, 0, 0, time.UTC)),
9696
},
97-
wantOutput: "Responses:",
97+
wantOutput: "RESPONSES",
9898
},
9999
{
100100
name: "from invalid format error",

pkg/commands/stats/usage.go

Lines changed: 3 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import (
55
"encoding/json"
66
"fmt"
77
"io"
8-
"maps"
9-
"slices"
108

119
"github.com/fastly/go-fastly/v13/fastly"
1210

@@ -84,7 +82,8 @@ func (c *UsageCommand) execPlain(out io.Writer, input *fastly.GetUsageInput) err
8482
case "json":
8583
return writeUsageJSON(out, resp.Data)
8684
default:
87-
return writeUsageTable(out, resp.Data)
85+
text.PrintUsageTbl(out, resp.Data)
86+
return nil
8887
}
8988
}
9089

@@ -105,26 +104,9 @@ func (c *UsageCommand) execByService(out io.Writer, input *fastly.GetUsageInput)
105104
case "json":
106105
return writeUsageByServiceJSON(out, resp.Data)
107106
default:
108-
return writeUsageByServiceTable(out, resp.Data)
109-
}
110-
}
111-
112-
func writeUsageTable(out io.Writer, data *fastly.RegionsUsage) error {
113-
if data == nil {
107+
text.PrintUsageByServiceTbl(out, resp.Data)
114108
return nil
115109
}
116-
regions := slices.Sorted(maps.Keys(*data))
117-
for _, region := range regions {
118-
usage := (*data)[region]
119-
if usage == nil {
120-
continue
121-
}
122-
text.Output(out, "Region: %s", region)
123-
text.Output(out, " Bandwidth: %d", fastly.ToValue(usage.Bandwidth))
124-
text.Output(out, " Requests: %d", fastly.ToValue(usage.Requests))
125-
text.Output(out, " Compute Requests: %d", fastly.ToValue(usage.ComputeRequests))
126-
}
127-
return nil
128110
}
129111

130112
func writeUsageJSON(out io.Writer, data *fastly.RegionsUsage) error {
@@ -134,32 +116,6 @@ func writeUsageJSON(out io.Writer, data *fastly.RegionsUsage) error {
134116
return json.NewEncoder(out).Encode(usageToMap(*data))
135117
}
136118

137-
func writeUsageByServiceTable(out io.Writer, data *fastly.ServicesByRegionsUsage) error {
138-
if data == nil {
139-
return nil
140-
}
141-
regions := slices.Sorted(maps.Keys(*data))
142-
for _, region := range regions {
143-
services := (*data)[region]
144-
if services == nil {
145-
continue
146-
}
147-
text.Output(out, "Region: %s", region)
148-
serviceIDs := slices.Sorted(maps.Keys(*services))
149-
for _, svcID := range serviceIDs {
150-
usage := (*services)[svcID]
151-
if usage == nil {
152-
continue
153-
}
154-
text.Output(out, " Service: %s", svcID)
155-
text.Output(out, " Bandwidth: %d", fastly.ToValue(usage.Bandwidth))
156-
text.Output(out, " Requests: %d", fastly.ToValue(usage.Requests))
157-
text.Output(out, " Compute Requests: %d", fastly.ToValue(usage.ComputeRequests))
158-
}
159-
}
160-
return nil
161-
}
162-
163119
func writeUsageByServiceJSON(out io.Writer, data *fastly.ServicesByRegionsUsage) error {
164120
if data == nil {
165121
return json.NewEncoder(out).Encode(map[string]any{})

pkg/commands/stats/usage_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func TestUsage(t *testing.T) {
2929
name: "success plain",
3030
args: args("stats usage"),
3131
api: mock.API{GetUsageFn: getUsageOK},
32-
wantOutput: "Region: usa",
32+
wantOutput: "usa",
3333
},
3434
{
3535
name: "success json",
@@ -41,7 +41,7 @@ func TestUsage(t *testing.T) {
4141
name: "success by-service",
4242
args: args("stats usage --by-service"),
4343
api: mock.API{GetUsageByServiceFn: getUsageByServiceOK},
44-
wantOutput: "Service: svc123",
44+
wantOutput: "svc123",
4545
},
4646
{
4747
name: "success by-service json",
@@ -59,20 +59,20 @@ func TestUsage(t *testing.T) {
5959
name: "nil usage entry table skipped",
6060
args: args("stats usage"),
6161
api: mock.API{GetUsageFn: getUsageWithNilEntry},
62-
wantOutput: "Region: europe",
62+
wantOutput: "europe",
6363
},
6464
{
6565
name: "region filter plain",
6666
args: args("stats usage --region=europe"),
6767
api: mock.API{GetUsageFn: getUsageMultiRegion},
68-
wantOutput: "Region: europe",
68+
wantOutput: "europe",
6969
wantAbsent: "usa",
7070
},
7171
{
7272
name: "region filter by-service",
7373
args: args("stats usage --by-service --region=europe"),
7474
api: mock.API{GetUsageByServiceFn: getUsageByServiceMultiRegion},
75-
wantOutput: "Region: europe",
75+
wantOutput: "svc456",
7676
wantAbsent: "usa",
7777
},
7878
{

0 commit comments

Comments
 (0)