-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
263 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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,181 @@ | ||
package fastly | ||
|
||
import ( | ||
"encoding/json" | ||
"strconv" | ||
"strings" | ||
"time" | ||
) | ||
|
||
// DomainInspector represents the response format returned for a request to | ||
// the historical Domain Inspector metrics endpoint. | ||
type DomainInspector struct { | ||
Data []DomainData `mapstructure:"data"` | ||
Meta DomainMeta `mapstructure:"meta"` | ||
Status string `mapstructure:"status"` | ||
} | ||
|
||
// DomainData represents the series of values over time for a single | ||
// dimension combination. | ||
type DomainData struct { | ||
Dimensions map[string]string `mapstructure:"dimensions"` | ||
Values []DomainMetrics `mapstructure:"values"` | ||
} | ||
|
||
// DomainMetrics represents the possible metrics that can be returned by a call | ||
// to the Domain Inspector endpoints. | ||
type DomainMetrics struct { | ||
Bandwidth uint64 `mapstructure:"bandwidth"` | ||
BereqBodyBytes uint64 `mapstructure:"bereq_body_bytes"` | ||
BereqHeaderBytes uint64 `mapstructure:"bereq_header_bytes"` | ||
EdgeHitRatio float64 `mapstructure:"edge_hit_ratio"` | ||
EdgeHitRequests uint64 `mapstructure:"edge_hit_requests"` | ||
EdgeMissRequests uint64 `mapstructure:"edge_miss_requests"` | ||
EdgeRequests uint64 `mapstructure:"edge_requests"` | ||
EdgeRespBodyBytes uint64 `mapstructure:"edge_resp_body_bytes"` | ||
EdgeRespHeaderBytes uint64 `mapstructure:"edge_resp_header_bytes"` | ||
OriginFetchRespBodyBytes uint64 `mapstructure:"origin_fetch_resp_body_bytes"` | ||
OriginFetchRespHeaderBytes uint64 `mapstructure:"origin_fetch_resp_header_bytes"` | ||
OriginFetches uint64 `mapstructure:"origin_fetches"` | ||
OriginOffload float64 `mapstructure:"origin_offload"` | ||
OriginStatus1xx uint64 `mapstructure:"origin_status_1xx"` | ||
OriginStatus200 uint64 `mapstructure:"origin_status_200"` | ||
OriginStatus204 uint64 `mapstructure:"origin_status_204"` | ||
OriginStatus206 uint64 `mapstructure:"origin_status_206"` | ||
OriginStatus2xx uint64 `mapstructure:"origin_status_2xx"` | ||
OriginStatus301 uint64 `mapstructure:"origin_status_301"` | ||
OriginStatus302 uint64 `mapstructure:"origin_status_302"` | ||
OriginStatus304 uint64 `mapstructure:"origin_status_304"` | ||
OriginStatus3xx uint64 `mapstructure:"origin_status_3xx"` | ||
OriginStatus400 uint64 `mapstructure:"origin_status_400"` | ||
OriginStatus401 uint64 `mapstructure:"origin_status_401"` | ||
OriginStatus403 uint64 `mapstructure:"origin_status_403"` | ||
OriginStatus404 uint64 `mapstructure:"origin_status_404"` | ||
OriginStatus416 uint64 `mapstructure:"origin_status_416"` | ||
OriginStatus429 uint64 `mapstructure:"origin_status_429"` | ||
OriginStatus4xx uint64 `mapstructure:"origin_status_4xx"` | ||
OriginStatus500 uint64 `mapstructure:"origin_status_500"` | ||
OriginStatus501 uint64 `mapstructure:"origin_status_501"` | ||
OriginStatus502 uint64 `mapstructure:"origin_status_502"` | ||
OriginStatus503 uint64 `mapstructure:"origin_status_503"` | ||
OriginStatus504 uint64 `mapstructure:"origin_status_504"` | ||
OriginStatus505 uint64 `mapstructure:"origin_status_505"` | ||
OriginStatus5xx uint64 `mapstructure:"origin_status_5xx"` | ||
Requests uint64 `mapstructure:"requests"` | ||
RespBodyBytes uint64 `mapstructure:"resp_body_bytes"` | ||
RespHeaderBytes uint64 `mapstructure:"resp_header_bytes"` | ||
Status1xx uint64 `mapstructure:"status_1xx"` | ||
Status200 uint64 `mapstructure:"status_200"` | ||
Status204 uint64 `mapstructure:"status_204"` | ||
Status206 uint64 `mapstructure:"status_206"` | ||
Status2xx uint64 `mapstructure:"status_2xx"` | ||
Status301 uint64 `mapstructure:"status_301"` | ||
Status302 uint64 `mapstructure:"status_302"` | ||
Status304 uint64 `mapstructure:"status_304"` | ||
Status3xx uint64 `mapstructure:"status_3xx"` | ||
Status400 uint64 `mapstructure:"status_400"` | ||
Status401 uint64 `mapstructure:"status_401"` | ||
Status403 uint64 `mapstructure:"status_403"` | ||
Status404 uint64 `mapstructure:"status_404"` | ||
Status416 uint64 `mapstructure:"status_416"` | ||
Status429 uint64 `mapstructure:"status_429"` | ||
Status4xx uint64 `mapstructure:"status_4xx"` | ||
Status500 uint64 `mapstructure:"status_500"` | ||
Status501 uint64 `mapstructure:"status_501"` | ||
Status502 uint64 `mapstructure:"status_502"` | ||
Status503 uint64 `mapstructure:"status_503"` | ||
Status504 uint64 `mapstructure:"status_504"` | ||
Status505 uint64 `mapstructure:"status_505"` | ||
Status5xx uint64 `mapstructure:"status_5xx"` | ||
Timestamp uint64 `mapstructure:"timestamp"` | ||
} | ||
|
||
// DomainMeta is the meta section returned for /metrics/domain responses | ||
type DomainMeta struct { | ||
Downsample string `mapstructure:"downsample"` | ||
End string `mapstructure:"end"` | ||
Filters map[string]string `mapstructure:"filters"` | ||
GroupBy string `mapstructure:"group_by"` | ||
Limit int `mapstructure:"limit"` | ||
Metric string `mapstructure:"metric"` | ||
NextCursor string `mapstructure:"next_cursor"` | ||
Sort string `mapstructure:"sort"` | ||
Start string `mapstructure:"start"` | ||
} | ||
|
||
// GetDomainMetricsInput is the input to a DomainMetrics request. | ||
type GetDomainMetricsInput struct { | ||
// Cursor is the value from a previous response to retrieve the next page. To request the first page, this should be empty. | ||
Cursor string | ||
// Datacenters limits query to one or more specific POPs. | ||
Datacenters []string | ||
// Domains limit query to one or more specific domains. | ||
Domains []string | ||
// Downsample is the duration of sample windows. | ||
Downsample string | ||
// End is a valid ISO-8601-formatted date and time, or UNIX timestamp, indicating the exclusive end of the query time range. If not provided, a default is chosen based on the provided downsample value. | ||
End time.Time | ||
// GroupBy is the dimensions to return in the query. | ||
GroupBy []string | ||
// Limit is the limit of returned data | ||
Limit int | ||
// Metrics is the metric to retrieve. Up to ten metrics are accepted. | ||
Metrics []string | ||
// Regions limits query to one or more specific geographic regions. | ||
Regions []string | ||
// ServiceID is an alphanumeric string identifying the service. | ||
ServiceID string | ||
// Start is a valid ISO-8601-formatted date and time, or UNIX timestamp, indicating the inclusive start of the query time range. If not provided, a default is chosen based on the provided downsample value. | ||
Start time.Time | ||
} | ||
|
||
// GetDomainMetricsForService retrieves the specified resource. | ||
func (c *Client) GetDomainMetricsForService(i *GetDomainMetricsInput) (*DomainInspector, error) { | ||
var resp interface{} | ||
if err := c.GetDomainMetricsForServiceJSON(i, &resp); err != nil { | ||
return nil, err | ||
} | ||
|
||
var di *DomainInspector | ||
if err := decodeMap(resp, &di); err != nil { | ||
return nil, err | ||
} | ||
return di, nil | ||
} | ||
|
||
// GetDomainMetricsForServiceJSON retrieves the specified resource. | ||
func (c *Client) GetDomainMetricsForServiceJSON(i *GetDomainMetricsInput, dst interface{}) error { | ||
if i.ServiceID == "" { | ||
return ErrMissingServiceID | ||
} | ||
|
||
p := "/metrics/domains/services/" + i.ServiceID | ||
|
||
start := "" | ||
if !i.Start.IsZero() { | ||
start = strconv.FormatInt(i.Start.Unix(), 10) | ||
} | ||
end := "" | ||
if !i.End.IsZero() { | ||
end = strconv.FormatInt(i.End.Unix(), 10) | ||
} | ||
|
||
r, err := c.Get(p, &RequestOptions{ | ||
Params: map[string]string{ | ||
"start": start, | ||
"end": end, | ||
"downsample": i.Downsample, | ||
"metric": strings.Join(i.Metrics, ","), | ||
"domain": strings.Join(i.Domains, ","), | ||
"datacenter": strings.Join(i.Datacenters, ","), | ||
"region": strings.Join(i.Regions, ","), | ||
"cursor": i.Cursor, | ||
}, | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
defer r.Body.Close() | ||
|
||
return json.NewDecoder(r.Body).Decode(dst) | ||
} |
This file contains 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,34 @@ | ||
package fastly | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
) | ||
|
||
func TestClient_GetDomainMetricsForService(t *testing.T) { | ||
t.Parallel() | ||
|
||
// NOTE: Update this to a recent time when regenerating the test fixtures, | ||
// otherwise the data may be outside of retention and an error will be | ||
// returned. | ||
end := time.Date(2023, 11, 7, 0, 0, 0, 0, time.UTC) | ||
start := end.Add(-8 * time.Hour) | ||
var err error | ||
record(t, "domain_inspector/metrics_for_service", func(c *Client) { | ||
_, err = c.GetDomainMetricsForService(&GetDomainMetricsInput{ | ||
ServiceID: testServiceID, | ||
Start: start, | ||
End: end, | ||
Domains: []string{"domain_1.com", "domain_2.com"}, | ||
Datacenters: []string{"SJC", "STP"}, | ||
Metrics: []string{"resp_body_bytes", "status_2xx"}, | ||
GroupBy: []string{"domain"}, | ||
Downsample: "hour", | ||
Regions: []string{"usa"}, | ||
Cursor: "", | ||
}) | ||
}) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
} |
This file contains 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,48 @@ | ||
--- | ||
version: 1 | ||
interactions: | ||
- request: | ||
body: "" | ||
form: {} | ||
headers: | ||
User-Agent: | ||
- FastlyGo/8.6.4 (+github.com/fastly/go-fastly; go1.20.4) | ||
url: https://api.fastly.com/metrics/domains/services/7i6HN3TK9wS159v2gPAZ8A?cursor=&datacenter=SJC%2CSTP&domain=domain_1.com%2Cdomain_2.com&downsample=hour&end=1699315200&metric=resp_body_bytes%2Cstatus_2xx®ion=usa&start=1699286400 | ||
method: GET | ||
response: | ||
body: | | ||
{"data":[{"dimensions":{"domain":"domain_1.com"},"values":[{"resp_body_bytes":3441795,"status_2xx":20,"timestamp":1699286400},{"resp_body_bytes":3756657,"status_2xx":16,"timestamp":1699290000},{"resp_body_bytes":3531110,"status_2xx":13,"timestamp":1699293600},{"resp_body_bytes":3476768,"status_2xx":9,"timestamp":1699297200},{"resp_body_bytes":4810115,"status_2xx":16,"timestamp":1699300800},{"resp_body_bytes":5384860,"status_2xx":21,"timestamp":1699304400},{"resp_body_bytes":4037251,"status_2xx":11,"timestamp":1699308000},{"resp_body_bytes":7816494,"status_2xx":20,"timestamp":1699311600}]},{"dimensions":{"domain":"domain_2.com"},"values":[{"resp_body_bytes":13653987068,"status_2xx":516069,"timestamp":1699286400},{"resp_body_bytes":13565871035,"status_2xx":625752,"timestamp":1699290000},{"resp_body_bytes":13932434066,"status_2xx":522300,"timestamp":1699293600},{"resp_body_bytes":15202809344,"status_2xx":532950,"timestamp":1699297200},{"resp_body_bytes":16112253051,"status_2xx":517396,"timestamp":1699300800},{"resp_body_bytes":14427752268,"status_2xx":503554,"timestamp":1699304400},{"resp_body_bytes":13491682169,"status_2xx":488470,"timestamp":1699308000},{"resp_body_bytes":13376860809,"status_2xx":485002,"timestamp":1699311600}]}],"meta":{"start":"2023-11-06T16:00:00Z","end":"2023-11-07T00:00:00Z","downsample":"hour","metric":"resp_body_bytes,status_2xx","limit":100,"next_cursor":"","sort":"domain","group_by":"domain","filters":{"datacenters":"SJC,STP","domains":"domain_1.com,domain_2.com","regions":"usa"}},"status":"success"} | ||
headers: | ||
Accept-Ranges: | ||
- bytes | ||
Age: | ||
- "0" | ||
Cache-Control: | ||
- no-store | ||
Content-Length: | ||
- "1561" | ||
Content-Type: | ||
- application/json | ||
Date: | ||
- Tue, 07 Nov 2023 23:20:14 GMT | ||
Pragma: | ||
- no-cache | ||
Status: | ||
- 200 OK | ||
Strict-Transport-Security: | ||
- max-age=31536000 | ||
Vary: | ||
- Accept-Encoding | ||
Via: | ||
- 1.1 varnish, 1.1 varnish | ||
X-Cache: | ||
- MISS, MISS | ||
X-Cache-Hits: | ||
- 0, 0 | ||
X-Served-By: | ||
- cache-control-cp-aws-us-east-2-prod-4-CONTROL-AWS-UE2, cache-pao-kpao1770049-PAO | ||
X-Timer: | ||
- S1699399214.860266,VS0,VE398 | ||
status: 200 OK | ||
code: 200 | ||
duration: "" |