diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b3fca687d1b1e2e..888df101594d989 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -99,3 +99,71 @@ export default { would render as Screenshot 2024-02-20 at 14 29 22 + +## GraphQL API Explorer + +If you are adding a code snippet to the documentation that is an executable GraphQL query, you can add `graphql-api-explorer` right after `graphql` in the code block metadata (both must be present). This will render a button that allows users to open the query in the [GraphQL API Explorer](https://graphql.cloudflare.com/explorer). For example: + +```` +```graphql graphql-api-explorer title="A GraphQL query" +query GraphqlExample($zoneTag: string, $start: Time, $end: Time) { + viewer { + zones(filter: { zoneTag: $zoneTag }) { + firewallEventsAdaptive( + filter: { datetime_gt: $start, datetime_lt: $end } + limit: 2 + orderBy: [datetime_DESC] + ) { + action + datetime + host: clientRequestHTTPHost + } + } + } +} +``` +```` + +When a user selects the `Run in GraphQL API Explorer` button, the following variables will be pre-populated in the GraphQL API Explorer along with the query. + +:::note +The user must be logged in or have an API token saved to see the query and variables pre-populated. +::: + +``` +{"zoneTag":"ZONE_ID", "start":"2025-05-07T14:54:36Z", "end":"2025-05-07T20:54:36Z"} +``` + +### Conventions to auto populate `Variables` section in the GraphQL API Explorer + +By default, the `Variables` section will be automatically populated based on the variables used in the GraphQL query. + +- Any variable name that includes `start` and has a type of `Time` --> start: "2025-05-09T14:58:06Z" (6 hours from the current time) + - e.g. `datetimeStart` also has `start` keyword, so it will be recognized for a start time (or date) +- Any variable name that includes `end` and has a type of `Time` --> end: "2025-05-09T20:58:06Z" (current time) +- Any variable name that includes `start` and has a type of `Date` --> start: "2025-05-07" (24 hours from the current date) +- Any variable name that includes `end` and has a type of `Date` --> end: "2025-05-08" (current date) +- `zoneTag` and has a type of `string` --> zoneTag: "ZONE_ID" +- `accountTag` and has a type of `string` --> accountTag: "ACCOUNT_ID" +- Any variable name that includes `id` and has a type of `string` --> id: "REPLACE_WITH_ID" +- Any variable name and has a type of string --> anyString: "REPLACE_WITH_STRING" +- `limit` with type `*int*` --> limit: 100 + +In addition to the variables that are automatically populated, you can add custom variables by setting their values as a JSON string in the `graphql-api-explorer` metadata. + +```` +```graphql graphql-api-explorer='{"uID": "something"}' title="A GraphQL query" +query GraphqlExample($zoneTag: string, $start: Time, $end: Time) { + viewer { + zones(filter: { zoneTag: $zoneTag }) { + ... + } + } +} +```` + +The variables added via the metadata value will be merged with the automatically populated variables. + +``` +{"zoneTag":"ZONE_ID", "start":"2025-05-07T14:54:36Z", "end":"2025-05-07T20:54:36Z", "uId": "something"} +``` diff --git a/ec.config.mjs b/ec.config.mjs index c4f82356b58ee98..106589333a7f1b6 100644 --- a/ec.config.mjs +++ b/ec.config.mjs @@ -7,6 +7,7 @@ import lightTheme from "solarflare-theme/themes/cloudflare-light-color-theme.jso import pluginWorkersPlayground from "./src/plugins/expressive-code/workers-playground.js"; import pluginOutputFrame from "./src/plugins/expressive-code/output-frame.js"; import pluginDefaultTitles from "./src/plugins/expressive-code/default-titles.js"; +import pluginGraphqlApiExplorer from "./src/plugins/expressive-code/graphql-api-explorer.js"; import { pluginCollapsibleSections } from "@expressive-code/plugin-collapsible-sections"; @@ -16,6 +17,7 @@ export default defineEcConfig({ pluginOutputFrame(), pluginDefaultTitles(), pluginCollapsibleSections(), + pluginGraphqlApiExplorer(), ], themes: [darkTheme, lightTheme], styleOverrides: { diff --git a/src/content/docs/analytics/graphql-api/features/discovery/introspection.mdx b/src/content/docs/analytics/graphql-api/features/discovery/introspection.mdx index 4d4c23ac4c79479..2575a21ddb24687 100644 --- a/src/content/docs/analytics/graphql-api/features/discovery/introspection.mdx +++ b/src/content/docs/analytics/graphql-api/features/discovery/introspection.mdx @@ -3,7 +3,6 @@ pcx_content_type: reference title: Introspection sidebar: order: 41 - --- Cloudflare GraphQL API has a dynamic schema and exposes more than 70 datasets @@ -50,104 +49,108 @@ etc). Alternatively, you can also do it manually by using `__schema` node with the needed directives. -```graphql title="A typical introspection query" +```graphql graphql-api-explorer title="A typical introspection query" { - __schema { - queryType { name } - mutationType { name } - subscriptionType { name } - types { - ...FullType - } - directives { - name - description - locations - args { - ...InputValue - } - } - } + __schema { + queryType { + name + } + mutationType { + name + } + subscriptionType { + name + } + types { + ...FullType + } + directives { + name + description + locations + args { + ...InputValue + } + } + } } fragment TypeRef on __Type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + } + } + } + } + } + } + } } fragment InputValue on __InputValue { - name - description - type { ...TypeRef } - defaultValue + name + description + type { + ...TypeRef + } + defaultValue } fragment FullType on __Type { - kind - name - description - fields(includeDeprecated: true) { - name - description - args { - ...InputValue - } - type { - ...TypeRef - } - isDeprecated - deprecationReason - } - inputFields { - ...InputValue - } - interfaces { - ...TypeRef - } - enumValues(includeDeprecated: true) { - name - description - isDeprecated - deprecationReason - } - possibleTypes { - ...TypeRef - } + kind + name + description + fields(includeDeprecated: true) { + name + description + args { + ...InputValue + } + type { + ...TypeRef + } + isDeprecated + deprecationReason + } + inputFields { + ...InputValue + } + interfaces { + ...TypeRef + } + enumValues(includeDeprecated: true) { + name + description + isDeprecated + deprecationReason + } + possibleTypes { + ...TypeRef + } } ``` -For more details on how to send a GraphQL request with curl, please refer to -[this guide][4]. +For more details on how to send a GraphQL request with curl, please refer to [Execute a GraphQL query with curl][4]. [1]: https://graphql.org/learn/introspection/ - [2]: /analytics/graphql-api/features/discovery/settings/ - [3]: /analytics/graphql-api/getting-started/explore-graphql-schema/ - [4]: /analytics/graphql-api/getting-started/execute-graphql-query/ diff --git a/src/content/docs/analytics/graphql-api/features/discovery/settings.mdx b/src/content/docs/analytics/graphql-api/features/discovery/settings.mdx index 7f68840903aa50c..74d3b5622e61fdf 100644 --- a/src/content/docs/analytics/graphql-api/features/discovery/settings.mdx +++ b/src/content/docs/analytics/graphql-api/features/discovery/settings.mdx @@ -3,7 +3,6 @@ pcx_content_type: reference title: Settings node sidebar: order: 43 - --- Cloudflare GraphQL API exposes more than 70 datasets to its customers. These @@ -40,56 +39,56 @@ available for both zones and accounts scopes. Every subnode of `settings` node could consist of these fields: -* `enabled` - shows whether the node is available for a requester or not; -* `availableFields` - shows the list of fields available for a requester. If - it is a nested field, the path will be returned, like `sum_requests`; -* `maxPageSize` - retrieves the maximum number of records that can be returned -* `maxNumberOfFields` - answers on how many fields could be used in a single +- `enabled` - shows whether the node is available for a requester or not; +- `availableFields` - shows the list of fields available for a requester. If + it's a nested field, the path will be returned, like `sum_requests`; +- `maxPageSize` - retrieves the maximum number of records that can be returned +- `maxNumberOfFields` - answers on how many fields could be used in a single query for that node; -* `notOlderThan` - returns a number of seconds on how far back in time a query +- `notOlderThan` - returns a number of seconds on how far back in time a query can read; -* `maxDuration` - shows how wide the requested time range could be. +- `maxDuration` - shows how wide the requested time range could be. ## A sample query -```graphql title="Get boundaries of firewallEventsAdaptive node" -{ - viewer { - zones(filter: { zoneTag: $zoneTag }) { - settings { - firewallEventsAdaptive { - enabled - maxDuration - maxNumberOfFields - maxPageSize - notOlderThan - } - } - } - } +```graphql graphql-api-explorer title="Get boundaries of firewallEventsAdaptive node" +query SampleQuery($zoneTag: string) { + viewer { + zones(filter: { zoneTag: $zoneTag }) { + settings { + firewallEventsAdaptive { + enabled + maxDuration + maxNumberOfFields + maxPageSize + notOlderThan + } + } + } + } } ``` ```json title="firewallEventsAdaptive limits for a given user" { - "data": { - "viewer": { - "zones": [ - { - "settings": { - "firewallEventsAdaptive": { - "enabled": true, - "maxDuration": 259200, - "maxNumberOfFields": 30, - "maxPageSize": 10000, - "notOlderThan": 2678400 - } - } - } - ] - } - }, - "errors": null + "data": { + "viewer": { + "zones": [ + { + "settings": { + "firewallEventsAdaptive": { + "enabled": true, + "maxDuration": 259200, + "maxNumberOfFields": 30, + "maxPageSize": 10000, + "notOlderThan": 2678400 + } + } + } + ] + } + }, + "errors": null } ``` @@ -97,7 +96,5 @@ To get more details on how to execute queries, please refer to our how to get started [guides][3]. [1]: /analytics/graphql-api/limits/ - [2]: /analytics/graphql-api/features/discovery/introspection/ - [3]: /analytics/graphql-api/getting-started/ diff --git a/src/content/docs/analytics/graphql-api/features/filtering.mdx b/src/content/docs/analytics/graphql-api/features/filtering.mdx index 3fe9787ed97113b..4d5d42ab7987648 100644 --- a/src/content/docs/analytics/graphql-api/features/filtering.mdx +++ b/src/content/docs/analytics/graphql-api/features/filtering.mdx @@ -3,7 +3,6 @@ pcx_content_type: reference title: Filtering sidebar: order: 11 - --- Filters constrain queries to a particular account or set of zones, requests by date, or those from a specific user agent, for example. Without filters, queries can suffer performance degradation, results can exceed supported bounds, and the data returned can be noisy. @@ -14,9 +13,9 @@ The GraphQL filter is represented by the [GraphQL Input Object](https://graphql. You can use filters as an argument on the following resources: -* zones -* accounts -* tables (datasets) +- zones +- accounts +- tables (datasets) ### Zone filter @@ -51,10 +50,8 @@ You must specify an account filter when making an account-scoped query, and you :::note[Note] - Network Analytics queries require an Account ID (`accountTag`) filter. - ::: ### Table (dataset) filter @@ -114,20 +111,23 @@ The `like` operator is available for string comparisons and supports the `%` cha :::note -Filtering times are based on event start timestamps, which means requests that end after the filter may be included in queries (as long as they start within the given time). +Filtering times are based on event start timestamps, which means requests that end after the filter may be included in queries (as long as they start within the given time). ::: ### General example -```graphql -{ - viewer { - zones(filter: {zoneTag: $zoneTag}) { - httpRequestsAdaptiveGroups(filter: {datetime_gt: "2021-06-10T00:00:00Z", clientCountryName: "GB"}, limit: 1) { - count - } - } - } +```graphql graphql-api-explorer +query GeneralExample($zoneTag: string, $start: Time) { + viewer { + zones(filter: { zoneTag: $zoneTag }) { + httpRequestsAdaptiveGroups( + filter: { datetime_gt: $start, clientCountryName: "GB" } + limit: 1 + ) { + count + } + } + } } ``` @@ -229,7 +229,7 @@ WHERE has(ruleIDs, 'rule-id-1') AND has(ruleIDs, 'rule-id-2') ### Filter end users -Add the `requestSource` filter for `eyeball` to return request, data transfer, and visit data about only the end users of your website. This will exclude actions taken by Cloudflare products (for example, cache purge, healthchecks, Workers subrequests) on your zone. +Add the `requestSource` filter for `eyeball` to return request, data transfer, and visit data about only the end users of your website. This will exclude actions taken by Cloudflare products (for example, cache purge, healthchecks, Workers subrequests) on your zone. ## Subqueries (advanced filters) diff --git a/src/content/docs/analytics/graphql-api/features/nested-structures.mdx b/src/content/docs/analytics/graphql-api/features/nested-structures.mdx index 19d126c81a25b00..34b2a881ef7e7f8 100644 --- a/src/content/docs/analytics/graphql-api/features/nested-structures.mdx +++ b/src/content/docs/analytics/graphql-api/features/nested-structures.mdx @@ -3,7 +3,6 @@ pcx_content_type: reference title: Nested Structures sidebar: order: 17 - --- Two kinds of nested structures that are supported: **arrays** and **maps**. Fields of either of these types are arrays; when they are part part of query result, which is already an array of objects, they become nested arrays. @@ -12,8 +11,8 @@ Two kinds of nested structures that are supported: **arrays** and **maps**. Fiel The GraphQL API supports two different sorts of arrays: -* Some arrays contain scalar types (for example, `[String]`) and function like ordinary fields that [can be filtered](/analytics/graphql-api/features/filtering/) -* Some arrays contain more complex types (for example, `[Subrequest]`.) The following section describes their behaviour. +- Some arrays contain scalar types (for example, `[String]`) and function like ordinary fields that [can be filtered](/analytics/graphql-api/features/filtering/) +- Some arrays contain more complex types (for example, `[Subrequest]`.) The following section describes their behaviour. Arrays of non-scalar types behave as a single value. There is no way to paginate through, filter, filter by, group, or group by the array. @@ -137,19 +136,19 @@ Response: Query array fields in raw datasets: -```javascript -query NestedFields($zoneTag: string, $dateStart: string, $dateEnd: string, $datetimeStart: string, $datetimeEnd: string) { - viewer { - zones(filter: {zoneTag: $zoneTag}) { - events(limit: 2, filter: {datetime_geq: $datetimeStart,datetime_leq: $datetimeEnd}){ - matches { - ruleId - action - source - } - } - } - } +```graphql graphql-api-explorer +query NestedFields($zoneTag: string, $start: Time, $end: Time) { + viewer { + zones(filter: { zoneTag: $zoneTag }) { + events(limit: 2, filter: { datetime_geq: $start, datetime_leq: $end }) { + matches { + ruleId + action + source + } + } + } + } } ``` @@ -187,27 +186,39 @@ Example response: Query maps fields in aggregated datasets: -```javascript -query MapCapacity($zoneTag: string, $dateStart: string, $dateEnd: string, $datetimeStart: string, $datetimeEnd: string) { - viewer { - zones(filter: {zoneTag: $zoneTag}) { - httpRequests1mGroups( - limit: 10, - filter: {date_geq: $dateStart, date_leq: $dateEnd, datetime_geq: $datetimeStart, datetime_lt: $datetimeEnd}) { - sum { - countryMap { - clientCountryName - requests - bytes - threats - } - } - dimensions { - datetimeHour - } - } - } - } +```graphql graphql-api-explorer +query MapCapacity( + $zoneTag: string + $dateStart: Date + $dateEnd: Date + $start: Time + $end: Time +) { + viewer { + zones(filter: { zoneTag: $zoneTag }) { + httpRequests1mGroups( + limit: 10 + filter: { + date_geq: $dateStart + date_leq: $dateEnd + datetime_geq: $start + datetime_lt: $end + } + ) { + sum { + countryMap { + clientCountryName + requests + bytes + threats + } + } + dimensions { + datetimeHour + } + } + } + } } ``` diff --git a/src/content/docs/analytics/graphql-api/getting-started/querying-basics.mdx b/src/content/docs/analytics/graphql-api/getting-started/querying-basics.mdx index 8bae89397b2bfd0..c9815653b4e63a7 100644 --- a/src/content/docs/analytics/graphql-api/getting-started/querying-basics.mdx +++ b/src/content/docs/analytics/graphql-api/getting-started/querying-basics.mdx @@ -26,22 +26,22 @@ scope of what they can act on. You can apply filters at each node. A typical query against the Cloudflare GraphQL schema is made up of four main components: -* `viewer` - is the root node, -* `zones` or `accounts` - indicate the scope of the query, that is the domain +- `viewer` - is the root node, +- `zones` or `accounts` - indicate the scope of the query, that is the domain area or account you want to query. The `viewer` can access one `zones` or `accounts`, or both, -* **data node** or **dataset** - represent the data you want to query. `zones` +- **data node** or **dataset** - represent the data you want to query. `zones` or `accounts` may contain one or more datasets. To find out more about discovering nodes, please refer to [introspection][1], -* **fieldset** - a set of fields or nested fields of the **dataset**. +- **fieldset** - a set of fields or nested fields of the **dataset**. The query to Cloudflare GraphQL API must be sent over HTTP POST request with payload in JSON format that consists of these fields: ```json { - "query": "", - "variables": {} + "query": "", + "variables": {} } ``` @@ -56,38 +56,33 @@ In the following example, the GraphQL query fetches a `datetime`, `action`, and client request HTTP host as `host` field of 2 WAF events from zone-scoped `firewallEventsAdaptive` dataset. -```graphql title="A GraphQL query" -{ - viewer { - zones(filter: { zoneTag: $tag }) { - firewallEventsAdaptive( - filter: { - datetime_gt: $start - datetime_lt: $end - } - limit: 2 - orderBy: [ - datetime_DESC - ] - ) { - action - datetime - host: clientRequestHTTPHost - } - } - } +```graphql graphql-api-explorer title="A GraphQL query" +query ASingleDatasetExample($zoneTag: string, $start: Time, $end: Time) { + viewer { + zones(filter: { zoneTag: $zoneTag }) { + firewallEventsAdaptive( + filter: { datetime_gt: $start, datetime_lt: $end } + limit: 2 + orderBy: [datetime_DESC] + ) { + action + datetime + host: clientRequestHTTPHost + } + } + } } ``` -In the query above, we have variable placeholders: $tag, $start, and $end. We +In the query above, we have variable placeholders: $zoneTag, $start, and $end. We provide values for those placeholders alongside the query by placing them into `variables` field of the payload. Note that the examples below use the UTC timezone, indicated by the letter "Z". ```json title="A set of variables" { - "tag": "", - "start": "2020-08-03T02:07:05Z", - "end": "2020-08-03T17:07:05Z" + "zoneTag": "", + "start": "2020-08-03T02:07:05Z", + "end": "2020-08-03T17:07:05Z" } ``` @@ -98,27 +93,27 @@ execute a query with a curl [here][3]. ```json title="A sample of a response for a query above" { - "data": { - "viewer": { - "zones": [ - { - "firewallEventsAdaptive": [ - { - "action": "log", - "host": "cloudflare.guru", - "datetime": "2020-08-03T17:07:03Z" - }, - { - "action": "log", - "host": "cloudflare.guru", - "datetime": "2020-08-03T17:07:01Z" - } - ] - } - ] - } - }, - "errors": null + "data": { + "viewer": { + "zones": [ + { + "firewallEventsAdaptive": [ + { + "action": "log", + "host": "cloudflare.guru", + "datetime": "2020-08-03T17:07:03Z" + }, + { + "action": "log", + "host": "cloudflare.guru", + "datetime": "2020-08-03T17:07:01Z" + } + ] + } + ] + } + }, + "errors": null } ``` @@ -130,113 +125,109 @@ response would be delayed until all dataset queries got their results. If any fails during the execution, the entire query will be terminated, and the error will be returned. -```graphql title="A sample query for two datasets in a one go" -{ - viewer { - zones(filter: { zoneTag: $tag }) { - last10Events: firewallEventsAdaptive( - filter: { - datetime_gt: $start - datetime_lt: $end - } - limit: 10 - orderBy: [ - datetime_DESC - ] - ) { - action - datetime - host: clientRequestHTTPHost - } - top3DeviceTypes: httpRequestsAdaptiveGroups( - filter: { - date: $ts - } - limit: 10 - orderBy: [ - count_DESC - ] - ) { - count - dimensions { - device: clientDeviceType - } - } - } - } +```graphql graphql-api-explorer title="A sample query for two datasets in a one go" +query MultipleDatasetsExample( + $zoneTag: string + $start: Time + $end: Time + $ts: Date +) { + viewer { + zones(filter: { zoneTag: $zoneTag }) { + last10Events: firewallEventsAdaptive( + filter: { datetime_gt: $start, datetime_lt: $end } + limit: 10 + orderBy: [datetime_DESC] + ) { + action + datetime + host: clientRequestHTTPHost + } + top3DeviceTypes: httpRequestsAdaptiveGroups( + filter: { date: $ts } + limit: 10 + orderBy: [count_DESC] + ) { + count + dimensions { + device: clientDeviceType + } + } + } + } } ``` ```json title="A set of variables for the query above" { - "tag": "", - "start": "2022-10-02T00:26:49Z", - "end": "2022-10-04T14:26:49Z", - "ts": "2022-10-04" + "zoneTag": "", + "start": "2022-10-02T00:26:49Z", + "end": "2022-10-04T14:26:49Z", + "ts": "2022-10-04" } ``` ```json title="A sample response for the query with variables above" { - "data": { - "viewer": { - "zones": [ - { - "last10Events": [ - { - "action": "block", - "country": "TR", - "datetime": "2022-10-04T08:41:09Z" - }, - { - "action": "block", - "country": "TR", - "datetime": "2022-10-04T08:41:09Z" - }, - { - "action": "block", - "country": "RU", - "datetime": "2022-10-04T01:09:36Z" - }, - { - "action": "block", - "country": "US", - "datetime": "2022-10-03T14:26:49Z" - }, - { - "action": "block", - "country": "US", - "datetime": "2022-10-03T14:26:46Z" - }, - { - "action": "block", - "country": "CN", - "datetime": "2022-10-02T23:51:26Z" - }, - { - "action": "block", - "country": "TR", - "datetime": "2022-10-02T23:39:41Z" - }, - { - "action": "block", - "country": "TR", - "datetime": "2022-10-02T23:39:41Z" - } - ], - "top3DeviceTypes": [ - { - "count": 4580, - "dimensions": { - "device": "desktop" - } - } - ] - } - ] - } - }, - "errors": null + "data": { + "viewer": { + "zones": [ + { + "last10Events": [ + { + "action": "block", + "country": "TR", + "datetime": "2022-10-04T08:41:09Z" + }, + { + "action": "block", + "country": "TR", + "datetime": "2022-10-04T08:41:09Z" + }, + { + "action": "block", + "country": "RU", + "datetime": "2022-10-04T01:09:36Z" + }, + { + "action": "block", + "country": "US", + "datetime": "2022-10-03T14:26:49Z" + }, + { + "action": "block", + "country": "US", + "datetime": "2022-10-03T14:26:46Z" + }, + { + "action": "block", + "country": "CN", + "datetime": "2022-10-02T23:51:26Z" + }, + { + "action": "block", + "country": "TR", + "datetime": "2022-10-02T23:39:41Z" + }, + { + "action": "block", + "country": "TR", + "datetime": "2022-10-02T23:39:41Z" + } + ], + "top3DeviceTypes": [ + { + "count": 4580, + "dimensions": { + "device": "desktop" + } + } + ] + } + ] + } + }, + "errors": null } ``` @@ -246,27 +237,20 @@ Here are some helpful articles about working with the Cloudflare Analytics API a ### Cloudflare specific -* [How to find your zoneTag using the API][5] +- [How to find your zoneTag using the API][5] ### General info on the GraphQL framework -* [How to use GraphQL (tutorials)][6] -* [Thinking in Graphs][7] -* [What data can you can query in the GraphQL type system (schemas)][8] -* [How to pass variables in GraphiQL (Medium article with quick tips)][9] +- [How to use GraphQL (tutorials)][6] +- [Thinking in Graphs][7] +- [What data can you can query in the GraphQL type system (schemas)][8] +- [How to pass variables in GraphiQL (Medium article with quick tips)][9] [1]: /analytics/graphql-api/features/discovery/introspection/ - [2]: /analytics/graphql-api/getting-started/compose-graphql-query/ - [3]: /analytics/graphql-api/getting-started/execute-graphql-query/ - [5]: /fundamentals/setup/find-account-and-zone-ids/ - [6]: https://www.howtographql.com/ - [7]: https://graphql.org/learn/thinking-in-graphs/ - [8]: https://graphql.org/learn/schema/ - [9]: https://medium.com/graphql-mastery/graphql-quick-tip-how-to-pass-variables-into-a-mutation-in-graphiql-23ecff4add57 diff --git a/src/content/docs/analytics/graphql-api/migration-guides/graphql-api-analytics.mdx b/src/content/docs/analytics/graphql-api/migration-guides/graphql-api-analytics.mdx index 5359d1662714a3b..a601aaa5b663eec 100644 --- a/src/content/docs/analytics/graphql-api/migration-guides/graphql-api-analytics.mdx +++ b/src/content/docs/analytics/graphql-api/migration-guides/graphql-api-analytics.mdx @@ -3,10 +3,9 @@ title: HTTP Requests by Colo Groups to HTTP Requests by Adaptive Groups pcx_content_type: reference sidebar: order: 11 - --- -import { Details } from "~/components" +import { Details } from "~/components"; This guide shares considerations when migrating from the deprecated `httpRequests1mByColoGroups` and `httpRequests1dByColoGroups` GraphQL API nodes to the `httpRequestsAdaptiveGroups` GraphQL API node. @@ -14,94 +13,89 @@ For example, if you wanted to see which five data centers had the most number of ```graphql { - viewer { - zones(filter: {zoneTag: $zoneTag}) { - series: httpRequests1mByColoGroups( - limit: 5, - orderBy: [ sum_requests_DESC ], - filter: { - datetime_geq: $start - datetime_lt: $end - } - ) { - sum { - requests - bytes - } - dimensions { - coloCode - } - } - } - } + viewer { + zones(filter: { zoneTag: $zoneTag }) { + series: httpRequests1mByColoGroups( + limit: 5 + orderBy: [sum_requests_DESC] + filter: { datetime_geq: $start, datetime_lt: $end } + ) { + sum { + requests + bytes + } + dimensions { + coloCode + } + } + } + } } ``` -
```json { - "data": { - "viewer": { - "zones": [ - { - "series": [ - { - "dimensions": { - "coloCode": "LHR" - }, - "sum": { - "bytes": 18260055, - "requests": 4404 - } - }, - { - "dimensions": { - "coloCode": "AMS" - }, - "sum": { - "bytes": 17563009, - "requests": 4302 - } - }, - { - "dimensions": { - "coloCode": "CDG" - }, - "sum": { - "bytes": 17200434, - "requests": 4032 - } - }, - { - "dimensions": { - "coloCode": "PTY" - }, - "sum": { - "bytes": 10400209, - "requests": 2707 - } - }, - { - "dimensions": { - "coloCode": "JIB" - }, - "sum": { - "bytes": 9040105, - "requests": 2601 - } - } - ] - } - ] - } - }, - "errors": null + "data": { + "viewer": { + "zones": [ + { + "series": [ + { + "dimensions": { + "coloCode": "LHR" + }, + "sum": { + "bytes": 18260055, + "requests": 4404 + } + }, + { + "dimensions": { + "coloCode": "AMS" + }, + "sum": { + "bytes": 17563009, + "requests": 4302 + } + }, + { + "dimensions": { + "coloCode": "CDG" + }, + "sum": { + "bytes": 17200434, + "requests": 4032 + } + }, + { + "dimensions": { + "coloCode": "PTY" + }, + "sum": { + "bytes": 10400209, + "requests": 2707 + } + }, + { + "dimensions": { + "coloCode": "JIB" + }, + "sum": { + "bytes": 9040105, + "requests": 2601 + } + } + ] + } + ] + } + }, + "errors": null } ``` -
## `httpRequestsAdaptiveGroups` GraphQL API node @@ -110,131 +104,129 @@ With the deprecation of the `httpRequests1mByColoGroups` and `httpRequests1dByCo **Request** -```graphql -{ - viewer { - zones(filter: {zoneTag: $zoneTag}) { - series: httpRequestsAdaptiveGroups( - limit: 5, - orderBy: [ count_DESC ], - filter: { - datetime_geq: $start - datetime_lt: $end - requestSource: 'eyeball' - } - ) { - count - avg { - sampleInterval - } - sum { - visits - edgeResponseBytes - } - dimensions { - coloCode - } - } - } - } +```graphql graphql-api-explorer +query MigrationSample($zoneTag: string, $start: Time, $end: Time) { + viewer { + zones(filter: { zoneTag: $zoneTag }) { + series: httpRequestsAdaptiveGroups( + limit: 5 + orderBy: [count_DESC] + filter: { + datetime_geq: $start + datetime_lt: $end + requestSource: "eyeball" + } + ) { + count + avg { + sampleInterval + } + sum { + visits + edgeResponseBytes + } + dimensions { + coloCode + } + } + } + } } ``` -
```json { - "data": { - "viewer": { - "zones": [ - { - "series": [ - { - "avg": { - "sampleInterval": 10 - }, - "count": 4350, - "dimensions": { - "coloCode": "LHR" - }, - "sum": { - "edgeResponseBytes": 17860000, - "visits": 4120 - } - }, - { - "avg": { - "sampleInterval": 10 - }, - "count": 4210, - "dimensions": { - "coloCode": "AMS" - }, - "sum": { - "edgeResponseBytes": 17110000, - "visits": 3910 - } - }, - { - "avg": { - "sampleInterval": 10 - }, - "count": 3890, - "dimensions": { - "coloCode": "CDG" - }, - "sum": { - "edgeResponseBytes": 17050000, - "visits": 3700 - } - }, - { - "avg": { - "sampleInterval": 10 - }, - "count": 2550, - "dimensions": { - "coloCode": "PTY" - }, - "sum": { - "edgeResponseBytes": 10286000, - "visits": 2130 - } - }, - { - "avg": { - "sampleInterval": 10 - }, - "count": 2410, - "dimensions": { - "coloCode": "JIB" - }, - "sum": { - "edgeResponseBytes": 9029000, - "visits": 2080 - } - } - ] - } - ] - } - }, - "errors": null + "data": { + "viewer": { + "zones": [ + { + "series": [ + { + "avg": { + "sampleInterval": 10 + }, + "count": 4350, + "dimensions": { + "coloCode": "LHR" + }, + "sum": { + "edgeResponseBytes": 17860000, + "visits": 4120 + } + }, + { + "avg": { + "sampleInterval": 10 + }, + "count": 4210, + "dimensions": { + "coloCode": "AMS" + }, + "sum": { + "edgeResponseBytes": 17110000, + "visits": 3910 + } + }, + { + "avg": { + "sampleInterval": 10 + }, + "count": 3890, + "dimensions": { + "coloCode": "CDG" + }, + "sum": { + "edgeResponseBytes": 17050000, + "visits": 3700 + } + }, + { + "avg": { + "sampleInterval": 10 + }, + "count": 2550, + "dimensions": { + "coloCode": "PTY" + }, + "sum": { + "edgeResponseBytes": 10286000, + "visits": 2130 + } + }, + { + "avg": { + "sampleInterval": 10 + }, + "count": 2410, + "dimensions": { + "coloCode": "JIB" + }, + "sum": { + "edgeResponseBytes": 9029000, + "visits": 2080 + } + } + ] + } + ] + } + }, + "errors": null } ``` -
This query says: -* Given the indicated `zones`, `limit`, and `time range`. -* Fetch the total number of requests (as `count`), the total amount of data transfer (as `edgeResponseBytes` of `sum` object), and the total number of `visits` per data center. +- Given the indicated `zones`, `limit`, and `time range`. +- Fetch the total number of requests (as `count`), the total amount of data transfer (as `edgeResponseBytes` of `sum` object), and the total number of `visits` per data center. A few points to note: -* Adding the `requestSource` filter for `eyeball` returns request, data transfer, and visit data about only the end users of your website. -* Instead of `requests`, the `httpRequestsAdaptiveGroups` node reports `count`, which indicates the number of requests per data center. -* To measure data transfer, use `sum(edgeResponseBytes)`. Note that in the old API this was called `bandwidth` even though it actually measured data transfer. -* `unique visitors per colocation` is not supported in `httpRequestsAdaptiveGroups`, but the `httpRequestsAdaptiveGroups` API does support `visits`. A visit is defined as a page view that originated from a different website or direct link. Cloudflare checks where the HTTP referer does not match the hostname. One visit can consist of multiple page views. +- Adding the `requestSource` filter for `eyeball` returns request, data transfer, and visit data about only the end users of your website. +- Instead of `requests`, the `httpRequestsAdaptiveGroups` node reports `count`, which indicates the number of requests per data center. +- To measure data transfer, use `sum(edgeResponseBytes)`. Note that in the old API this was called `bandwidth` even though it actually measured data transfer. +- `unique visitors per colocation` is not supported in `httpRequestsAdaptiveGroups`, but the `httpRequestsAdaptiveGroups` API does support `visits`. A visit is defined as a page view that originated from a different website or direct link. Cloudflare checks where the HTTP referer does not match the hostname. One visit can consist of multiple page views. diff --git a/src/content/docs/analytics/graphql-api/migration-guides/zone-analytics.mdx b/src/content/docs/analytics/graphql-api/migration-guides/zone-analytics.mdx index 73436a6782d15ea..8ef9d4806b0ea1a 100644 --- a/src/content/docs/analytics/graphql-api/migration-guides/zone-analytics.mdx +++ b/src/content/docs/analytics/graphql-api/migration-guides/zone-analytics.mdx @@ -3,10 +3,9 @@ pcx_content_type: reference title: Zone Analytics to GraphQL Analytics sidebar: order: 12 - --- -import { Details } from "~/components" +import { Details } from "~/components"; The Zone Analytics API allows you to get request data by zone. It offers optional `since` and `until` parameters to specify the request time period and a `continuous` parameter to indicate whether the time period should be moved backward to find a period with completely aggregated data. @@ -17,496 +16,496 @@ curl "https://api.cloudflare.com/client/v4/zones//analytics/dashboard?s --header "Authorization: Bearer " --silent | jq . ``` -
```json { - "success": true, - "query": { - "since": "2019-09-08T20:00:00Z", - "until": "2019-09-08T20:02:00Z", - "time_delta": 1 - }, - "errors": [], - "messages": [], - "result": { - "timeseries": [ - { - "since": "2019-09-08T20:00:00Z", - "until": "2019-09-08T20:01:00Z", - "requests": { - "all": 15, - "cached": 12, - "uncached": 3, - "ssl": { - "encrypted": 13, - "unencrypted": 2 - }, - "http_status": { - "200": 4, - "403": 11 - }, - "content_type": { - "html": 12, - "png": 3 - }, - "country": { - "CN": 6, - "IE": 1, - "US": 3, - "VN": 5 - }, - "ip_class": { - "monitoringService": 4, - "noRecord": 11 - }, - "ssl_protocol": { - "TLSv1.2": 13, - "none": 2 - } - }, - "bandwidth": { - "all": 312740, - "cached": 309930, - "uncached": 2810, - "ssl": { - "encrypted": 309276, - "unencrypted": 3464 - }, - "ssl_protocol": { - "TLSv1.2": 13, - "none": 2 - }, - "content_type": { - "html": 32150, - "png": 280590 - }, - "country": { - "CN": 10797, - "IE": 98224, - "US": 185176, - "VN": 18543 - } - }, - "threats": { - "all": 6, - "type": { - "user.ban.ctry": 6 - }, - "country": { - "CN": 6 - } - }, - "pageviews": { - "all": 1, - "search_engine": { - "pingdom": 1 - } - }, - "uniques": { - "all": 11 - } - }, - { - "since": "2019-09-08T20:01:00Z", - "until": "2019-09-08T20:02:00Z", - "requests": { - "all": 4, - "cached": 1, - "uncached": 3, - "ssl": { - "encrypted": 4, - "unencrypted": 0 - }, - "http_status": { - "200": 4 - }, - "content_type": { - "html": 1, - "png": 3 - }, - "country": { - "CA": 2, - "US": 2 - }, - "ip_class": { - "monitoringService": 4 - }, - "ssl_protocol": { - "TLSv1.2": 4 - } - }, - "bandwidth": { - "all": 283399, - "cached": 280590, - "uncached": 2809, - "ssl": { - "encrypted": 283399, - "unencrypted": 0 - }, - "ssl_protocol": { - "TLSv1.2": 4 - }, - "content_type": { - "html": 2809, - "png": 280590 - }, - "country": { - "CA": 101033, - "US": 182366 - } - }, - "threats": { - "all": 0, - "type": {}, - "country": {} - }, - "pageviews": { - "all": 1, - "search_engine": { - "pingdom": 1 - } - }, - "uniques": { - "all": 4 - } - } - ], - "totals": { - "since": "2019-09-08T20:00:00Z", - "until": "2019-09-08T20:02:00Z", - "requests": { - "all": 19, - "cached": 13, - "uncached": 6, - "ssl": { - "encrypted": 17, - "unencrypted": 2 - }, - "http_status": { - "200": 8, - "403": 11 - }, - "content_type": { - "html": 13, - "png": 6 - }, - "country": { - "CA": 2, - "CN": 6, - "IE": 1, - "US": 5, - "VN": 5 - }, - "ip_class": { - "monitoringService": 8, - "noRecord": 11 - }, - "ssl_protocol": { - "TLSv1.2": 17, - "none": 2 - } - }, - "bandwidth": { - "all": 596139, - "cached": 590520, - "uncached": 5619, - "ssl": { - "encrypted": 592675, - "unencrypted": 3464 - }, - "ssl_protocol": { - "TLSv1.2": 17, - "none": 2 - }, - "content_type": { - "html": 34959, - "png": 561180 - }, - "country": { - "CA": 101033, - "CN": 10797, - "IE": 98224, - "US": 367542, - "VN": 18543 - } - }, - "threats": { - "all": 6, - "type": { - "user.ban.ctry": 6 - }, - "country": { - "CN": 6 - } - }, - "pageviews": { - "all": 2, - "search_engine": { - "pingdom": 2 - } - }, - "uniques": { - "all": 15 - } - } - } + "success": true, + "query": { + "since": "2019-09-08T20:00:00Z", + "until": "2019-09-08T20:02:00Z", + "time_delta": 1 + }, + "errors": [], + "messages": [], + "result": { + "timeseries": [ + { + "since": "2019-09-08T20:00:00Z", + "until": "2019-09-08T20:01:00Z", + "requests": { + "all": 15, + "cached": 12, + "uncached": 3, + "ssl": { + "encrypted": 13, + "unencrypted": 2 + }, + "http_status": { + "200": 4, + "403": 11 + }, + "content_type": { + "html": 12, + "png": 3 + }, + "country": { + "CN": 6, + "IE": 1, + "US": 3, + "VN": 5 + }, + "ip_class": { + "monitoringService": 4, + "noRecord": 11 + }, + "ssl_protocol": { + "TLSv1.2": 13, + "none": 2 + } + }, + "bandwidth": { + "all": 312740, + "cached": 309930, + "uncached": 2810, + "ssl": { + "encrypted": 309276, + "unencrypted": 3464 + }, + "ssl_protocol": { + "TLSv1.2": 13, + "none": 2 + }, + "content_type": { + "html": 32150, + "png": 280590 + }, + "country": { + "CN": 10797, + "IE": 98224, + "US": 185176, + "VN": 18543 + } + }, + "threats": { + "all": 6, + "type": { + "user.ban.ctry": 6 + }, + "country": { + "CN": 6 + } + }, + "pageviews": { + "all": 1, + "search_engine": { + "pingdom": 1 + } + }, + "uniques": { + "all": 11 + } + }, + { + "since": "2019-09-08T20:01:00Z", + "until": "2019-09-08T20:02:00Z", + "requests": { + "all": 4, + "cached": 1, + "uncached": 3, + "ssl": { + "encrypted": 4, + "unencrypted": 0 + }, + "http_status": { + "200": 4 + }, + "content_type": { + "html": 1, + "png": 3 + }, + "country": { + "CA": 2, + "US": 2 + }, + "ip_class": { + "monitoringService": 4 + }, + "ssl_protocol": { + "TLSv1.2": 4 + } + }, + "bandwidth": { + "all": 283399, + "cached": 280590, + "uncached": 2809, + "ssl": { + "encrypted": 283399, + "unencrypted": 0 + }, + "ssl_protocol": { + "TLSv1.2": 4 + }, + "content_type": { + "html": 2809, + "png": 280590 + }, + "country": { + "CA": 101033, + "US": 182366 + } + }, + "threats": { + "all": 0, + "type": {}, + "country": {} + }, + "pageviews": { + "all": 1, + "search_engine": { + "pingdom": 1 + } + }, + "uniques": { + "all": 4 + } + } + ], + "totals": { + "since": "2019-09-08T20:00:00Z", + "until": "2019-09-08T20:02:00Z", + "requests": { + "all": 19, + "cached": 13, + "uncached": 6, + "ssl": { + "encrypted": 17, + "unencrypted": 2 + }, + "http_status": { + "200": 8, + "403": 11 + }, + "content_type": { + "html": 13, + "png": 6 + }, + "country": { + "CA": 2, + "CN": 6, + "IE": 1, + "US": 5, + "VN": 5 + }, + "ip_class": { + "monitoringService": 8, + "noRecord": 11 + }, + "ssl_protocol": { + "TLSv1.2": 17, + "none": 2 + } + }, + "bandwidth": { + "all": 596139, + "cached": 590520, + "uncached": 5619, + "ssl": { + "encrypted": 592675, + "unencrypted": 3464 + }, + "ssl_protocol": { + "TLSv1.2": 17, + "none": 2 + }, + "content_type": { + "html": 34959, + "png": 561180 + }, + "country": { + "CA": 101033, + "CN": 10797, + "IE": 98224, + "US": 367542, + "VN": 18543 + } + }, + "threats": { + "all": 6, + "type": { + "user.ban.ctry": 6 + }, + "country": { + "CN": 6 + } + }, + "pageviews": { + "all": 2, + "search_engine": { + "pingdom": 2 + } + }, + "uniques": { + "all": 15 + } + } + } } ``` -
As you can see from the response, Zone Analytics returns metrics along many dimensions and does not give you the option to control what you receive. With GraphQL Analytics, you can ask for only the data that you need. However, if you wanted to get exactly the same metrics and dimensions as you would from Zone Analytics, here is the query you would make: -```txt -{ - viewer { - zones(filter: {zoneTag: }) { - httpRequests1mGroups(orderBy: [datetimeMinute_ASC], limit: 100, filter: {datetime_geq: "2019-09-08T20:00:00Z", datetime_lt: "2019-09-08T20:02:00Z"}) { - dimensions { - datetimeMinute - } - sum { - browserMap { - pageViews - uaBrowserFamily - } - bytes - cachedBytes - cachedRequests - contentTypeMap { - bytes - requests - edgeResponseContentTypeName - } - clientSSLMap { - requests - clientSSLProtocol - } - countryMap { - bytes - requests - threats - clientCountryName - } - encryptedBytes - encryptedRequests - ipClassMap { - requests - ipType - } - pageViews - requests - responseStatusMap { - requests - edgeResponseStatus - } - threats - threatPathingMap { - requests - threatPathingName - } - } - uniq { - uniques - } - } - } - } +```graphql graphql-api-explorer +query ZoneAnalyticsMigrationSample($zoneTag: string, $start: Time, $end: Time) { + viewer { + zones(filter: { zoneTag: $zoneTag }) { + httpRequests1mGroups( + orderBy: [datetimeFiveMinutes_ASC] + limit: 100 + filter: { datetime_geq: $start, datetime_lt: $end } + ) { + dimensions { + datetimeFiveMinutes + } + sum { + browserMap { + pageViews + uaBrowserFamily + } + bytes + cachedBytes + cachedRequests + contentTypeMap { + bytes + requests + edgeResponseContentTypeName + } + clientSSLMap { + requests + clientSSLProtocol + } + countryMap { + bytes + requests + threats + clientCountryName + } + encryptedBytes + encryptedRequests + ipClassMap { + requests + ipType + } + pageViews + requests + responseStatusMap { + requests + edgeResponseStatus + } + threats + threatPathingMap { + requests + threatPathingName + } + } + uniq { + uniques + } + } + } + } } ``` -
```json { - "data": { - "viewer": { - "zones": [ - { - "httpRequests1mGroups": [ - { - "dimensions": { - "datetimeMinute": "2019-09-08T20:00:00Z" - }, - "sum": { - "browserMap": [ - { - "pageViews": 1, - "uaBrowserFamily": "PingdomBot" - } - ], - "bytes": 312740, - "cachedBytes": 309930, - "cachedRequests": 12, - "clientSSLMap": [ - { - "clientSSLProtocol": "none", - "requests": 2 - }, - { - "clientSSLProtocol": "TLSv1.2", - "requests": 13 - } - ], - "contentTypeMap": [ - { - "bytes": 280590, - "edgeResponseContentTypeName": "png", - "requests": 3 - }, - { - "bytes": 32150, - "edgeResponseContentTypeName": "html", - "requests": 12 - } - ], - "countryMap": [ - { - "bytes": 10797, - "clientCountryName": "CN", - "requests": 6, - "threats": 6 - }, - { - "bytes": 98224, - "clientCountryName": "IE", - "requests": 1, - "threats": 0 - }, - { - "bytes": 185176, - "clientCountryName": "US", - "requests": 3, - "threats": 0 - }, - { - "bytes": 18543, - "clientCountryName": "VN", - "requests": 5, - "threats": 0 - } - ], - "encryptedBytes": 309276, - "encryptedRequests": 13, - "ipClassMap": [ - { - "ipType": "monitoringService", - "requests": 4 - }, - { - "ipType": "noRecord", - "requests": 11 - } - ], - "pageViews": 1, - "requests": 15, - "responseStatusMap": [ - { - "edgeResponseStatus": 200, - "requests": 4 - }, - { - "edgeResponseStatus": 403, - "requests": 11 - } - ], - "threatPathingMap": [ - { - "requests": 6, - "threatPathingName": "user.ban.ctry" - } - ], - "threats": 6 - }, - "uniq": { - "uniques": 11 - } - }, - { - "dimensions": { - "datetimeMinute": "2019-09-08T20:01:00Z" - }, - "sum": { - "browserMap": [ - { - "pageViews": 1, - "uaBrowserFamily": "PingdomBot" - } - ], - "bytes": 283399, - "cachedBytes": 280590, - "cachedRequests": 1, - "clientSSLMap": [ - { - "clientSSLProtocol": "TLSv1.2", - "requests": 4 - } - ], - "contentTypeMap": [ - { - "bytes": 280590, - "edgeResponseContentTypeName": "png", - "requests": 3 - }, - { - "bytes": 2809, - "edgeResponseContentTypeName": "html", - "requests": 1 - } - ], - "countryMap": [ - { - "bytes": 101033, - "clientCountryName": "CA", - "requests": 2, - "threats": 0 - }, - { - "bytes": 182366, - "clientCountryName": "US", - "requests": 2, - "threats": 0 - } - ], - "encryptedBytes": 283399, - "encryptedRequests": 4, - "ipClassMap": [ - { - "ipType": "monitoringService", - "requests": 4 - } - ], - "pageViews": 1, - "requests": 4, - "responseStatusMap": [ - { - "edgeResponseStatus": 200, - "requests": 4 - } - ], - "threatPathingMap": [], - "threats": 0 - }, - "uniq": { - "uniques": 4 - } - } - ] - } - ] - } - }, - "errors": null + "data": { + "viewer": { + "zones": [ + { + "httpRequests1mGroups": [ + { + "dimensions": { + "datetimeFiveMinutes": "2019-09-08T20:00:00Z" + }, + "sum": { + "browserMap": [ + { + "pageViews": 1, + "uaBrowserFamily": "PingdomBot" + } + ], + "bytes": 312740, + "cachedBytes": 309930, + "cachedRequests": 12, + "clientSSLMap": [ + { + "clientSSLProtocol": "none", + "requests": 2 + }, + { + "clientSSLProtocol": "TLSv1.2", + "requests": 13 + } + ], + "contentTypeMap": [ + { + "bytes": 280590, + "edgeResponseContentTypeName": "png", + "requests": 3 + }, + { + "bytes": 32150, + "edgeResponseContentTypeName": "html", + "requests": 12 + } + ], + "countryMap": [ + { + "bytes": 10797, + "clientCountryName": "CN", + "requests": 6, + "threats": 6 + }, + { + "bytes": 98224, + "clientCountryName": "IE", + "requests": 1, + "threats": 0 + }, + { + "bytes": 185176, + "clientCountryName": "US", + "requests": 3, + "threats": 0 + }, + { + "bytes": 18543, + "clientCountryName": "VN", + "requests": 5, + "threats": 0 + } + ], + "encryptedBytes": 309276, + "encryptedRequests": 13, + "ipClassMap": [ + { + "ipType": "monitoringService", + "requests": 4 + }, + { + "ipType": "noRecord", + "requests": 11 + } + ], + "pageViews": 1, + "requests": 15, + "responseStatusMap": [ + { + "edgeResponseStatus": 200, + "requests": 4 + }, + { + "edgeResponseStatus": 403, + "requests": 11 + } + ], + "threatPathingMap": [ + { + "requests": 6, + "threatPathingName": "user.ban.ctry" + } + ], + "threats": 6 + }, + "uniq": { + "uniques": 11 + } + }, + { + "dimensions": { + "datetimeFiveMinutes": "2019-09-08T20:01:00Z" + }, + "sum": { + "browserMap": [ + { + "pageViews": 1, + "uaBrowserFamily": "PingdomBot" + } + ], + "bytes": 283399, + "cachedBytes": 280590, + "cachedRequests": 1, + "clientSSLMap": [ + { + "clientSSLProtocol": "TLSv1.2", + "requests": 4 + } + ], + "contentTypeMap": [ + { + "bytes": 280590, + "edgeResponseContentTypeName": "png", + "requests": 3 + }, + { + "bytes": 2809, + "edgeResponseContentTypeName": "html", + "requests": 1 + } + ], + "countryMap": [ + { + "bytes": 101033, + "clientCountryName": "CA", + "requests": 2, + "threats": 0 + }, + { + "bytes": 182366, + "clientCountryName": "US", + "requests": 2, + "threats": 0 + } + ], + "encryptedBytes": 283399, + "encryptedRequests": 4, + "ipClassMap": [ + { + "ipType": "monitoringService", + "requests": 4 + } + ], + "pageViews": 1, + "requests": 4, + "responseStatusMap": [ + { + "edgeResponseStatus": 200, + "requests": 4 + } + ], + "threatPathingMap": [], + "threats": 0 + }, + "uniq": { + "uniques": 4 + } + } + ] + } + ] + } + }, + "errors": null } ``` -
Notice that you can specify the request time period using a dataset filter (refer to [Filtering](/analytics/graphql-api/features/filtering/)). The `continuous` parameter is no longer needed because GraphQL Analytics is designed to provide data as soon as it is available. -Also, if you want to get the totals for a particular period, rather than a breakdown by time period, simply remove the `datetimeMinute` field under `dimensions`. +Also, if you want to get the totals for a particular period, rather than a breakdown by time period, simply remove the `datetimeFiveMinutes` field under `dimensions`. diff --git a/src/content/docs/analytics/graphql-api/tutorials/use-graphql-create-widgets.mdx b/src/content/docs/analytics/graphql-api/tutorials/use-graphql-create-widgets.mdx index 7633510c5056f4c..ff1039ca2a98bab 100644 --- a/src/content/docs/analytics/graphql-api/tutorials/use-graphql-create-widgets.mdx +++ b/src/content/docs/analytics/graphql-api/tutorials/use-graphql-create-widgets.mdx @@ -3,25 +3,24 @@ pcx_content_type: example title: Use GraphQL to create widgets sidebar: order: 46 - --- This article presents examples of queries you can use to populate your own dashboard. -* [Parameters and filters](#parameters-and-filters) -* [Timeseries graph](#timeseries-graph) -* [Activity log](#activity-log) -* [Top N cards - source](#top-n-cards---source) -* [Top N cards - destination](#top-n-cards---destination) -* [TCP Flags](#tcp-flags) -* [Executive summary](#executive-summary) +- [Parameters and filters](#parameters-and-filters) +- [Timeseries graph](#timeseries-graph) +- [Activity log](#activity-log) +- [Top N cards - source](#top-n-cards---source) +- [Top N cards - destination](#top-n-cards---destination) +- [TCP Flags](#tcp-flags) +- [Executive summary](#executive-summary) Use this workflow to build and test queries: -* Install and configure the [GraphiQL](https://www.gatsbyjs.com/docs/how-to/querying-data/running-queries-with-graphiql/) app to authenticate to the Cloudflare Analytics GraphQL API. Cloudflare recommends token authentication. Refer to [Configure an Analytics API token](/analytics/graphql-api/getting-started/authentication/api-token-auth/), for more information. -* Construct the queries in the GraphiQL. You can use the introspective documentation in the GraphQL client to explore the nodes available. For further information about queries, refer to [Querying basics](/analytics/graphql-api/getting-started/querying-basics/). -* Test your queries by running them from GraphiQL or by passing them as the payload in a cURL request to the GraphQL API endpoint. -* Use the queries in your application to provide data for your dashboard widgets. +- Install and configure the [GraphiQL](https://www.gatsbyjs.com/docs/how-to/querying-data/running-queries-with-graphiql/) app to authenticate to the Cloudflare Analytics GraphQL API. Cloudflare recommends token authentication. Refer to [Configure an Analytics API token](/analytics/graphql-api/getting-started/authentication/api-token-auth/), for more information. +- Construct the queries in the GraphiQL. You can use the introspective documentation in the GraphQL client to explore the nodes available. For further information about queries, refer to [Querying basics](/analytics/graphql-api/getting-started/querying-basics/). +- Test your queries by running them from GraphiQL or by passing them as the payload in a cURL request to the GraphQL API endpoint. +- Use the queries in your application to provide data for your dashboard widgets. ## Parameters and filters @@ -33,13 +32,10 @@ The following example queries for data with dates greater than or equal to `date ```json title="Account and query time interval settings" { - "accountTag": "{account-id}", - "filter": { - "AND":[ - {"date_geq": "2020-01-19"}, - {"date_leq": "2020-01-20"} - ] - } + "accountTag": "{account-id}", + "filter": { + "AND": [{ "date_geq": "2020-01-19" }, { "date_leq": "2020-01-20" }] + } } ``` @@ -48,164 +44,175 @@ This table lists Network Analytics datasets (nodes) and the `datetimeDimension` When you want an aggregated view of data, use the `Groups` query nodes. For example, the `ipFlows1mAttacksGroups` dataset represents minute-wise rollup reports of attack activity. For more detail, refer to [Datasets](/analytics/graphql-api/features/data-sets/). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Time SelectionQuery nodedatetimeDimension
Last weekipFlows1dGroupsdate
Last monthipFlows1dGroupsdate
24 hoursipFlows1mGroupsdatetimeFifteenMinutes
12 hoursipFlows1mGroupsdatetimeFifteenMinutes
6 hoursipFlows1mGroupsdatetimeFiveMinutes
30 minsipFlows1mGroupsdatetimeMinute
Custom rangeDependent on range selectedDependent on range selected
+ Time Selection + + Query node + + datetimeDimension +
Last weekipFlows1dGroupsdate
Last monthipFlows1dGroupsdate
24 hoursipFlows1mGroupsdatetimeFifteenMinutes
12 hoursipFlows1mGroupsdatetimeFifteenMinutes
6 hoursipFlows1mGroupsdatetimeFiveMinutes
30 minsipFlows1mGroupsdatetimeMinute
Custom rangeDependent on range selectedDependent on range selected
The table below lists the start and end time attributes that are valid for query nodes representing different time ranges. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Query nodeStart day / time filterEnd day / time filter
ipFlows1mGroupsdatetimeMinute_geqdatetimeMinute_leq
ipFlows1mAttacksGroupsdate_geqdate_leq
ipFlows1hGroupsdatetimeHour_geqdatetimeHour_leq
ipFlows1dGroupsdate_geqdate_leq
+ Query node + + Start day / time filter + + End day / time filter +
ipFlows1mGroupsdatetimeMinute_geqdatetimeMinute_leq
ipFlows1mAttacksGroupsdate_geqdate_leq
ipFlows1hGroupsdatetimeHour_geqdatetimeHour_leq
ipFlows1dGroupsdate_geqdate_leq
## Timeseries graph Use the following query to build the timeseries graph in network analytics: -```graphql title="Timeseries graph" +```graphql graphql-api-explorer title="Timeseries graph" query ipFlowTimeseries( - $accountTag: string - $filter: AccountIpFlows1mGroupsFilter_InputObject - ) { - viewer { - accounts(filter: { accountTag: $accountTag }) { - ipFlows1mGroups( - limit: 1000 - filter: $filter - orderBy: datetimeMinute_ASC - ) { - dimensions { - timestamp: datetimeMinute - attackMitigationType - attackId - } - sum { - bits - packets - } - } - } - } - } + $accountTag: string + $filter: AccountIpFlows1mGroupsFilter_InputObject +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + ipFlows1mGroups( + limit: 1000 + filter: $filter + orderBy: datetimeMinute_ASC + ) { + dimensions { + timestamp: datetimeMinute + attackMitigationType + attackId + } + sum { + bits + packets + } + } + } + } +} ``` ## Activity log This query returns an activity log summarizing minute-wise rollups of attack traffic in IP flows. The query groups the data by the fields listed in the `dimensions` object. -```graphql title="Activity log query" +```graphql graphql-api-explorer title="Activity log query" query ipFlowEventLog( - $accountTag: string - $filter: AccountIpFlows1mAttacksGroupsFilter_InputObject - ) { - viewer { - accounts(filter: { accountTag: $accountTag }) { - ipFlows1mAttacksGroups( - limit: 10 - filter: $filter - orderBy: [min_datetimeMinute_ASC] - ) { - dimensions { - attackId - attackDestinationIP - attackDestinationPort - attackMitigationType - attackSourcePort - attackType - } - avg { - bitsPerSecond - packetsPerSecond - } - min { - datetimeMinute - bitsPerSecond - packetsPerSecond - } - max { - datetimeMinute - bitsPerSecond - packetsPerSecond - } - sum { - bits - packets - } - } - } - } - } - + $accountTag: string + $filter: AccountIpFlows1mAttacksGroupsFilter_InputObject +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + ipFlows1mAttacksGroups( + limit: 10 + filter: $filter + orderBy: [min_datetimeMinute_ASC] + ) { + dimensions { + attackId + attackDestinationIP + attackDestinationPort + attackMitigationType + attackSourcePort + attackType + } + avg { + bitsPerSecond + packetsPerSecond + } + min { + datetimeMinute + bitsPerSecond + packetsPerSecond + } + max { + datetimeMinute + bitsPerSecond + packetsPerSecond + } + sum { + bits + packets + } + } + } + } +} ``` ## Top N cards - source @@ -213,7 +220,7 @@ query ipFlowEventLog( This query returns data about the top source IPs. The `limit` parameter controls the amount of records returned for each node. In the following code, the highlighted lines indicate where you configure `limit`. -```graphql title="Top N Cards query" {9,22,35,47,60,72} +```graphql graphql-api-explorer title="Top N Cards query" {9,22,35,47,60,72} query GetTopNBySource( $accountTag: string $filter: AccountIpFlows1mGroupsFilter_InputObject @@ -306,7 +313,7 @@ query GetTopNBySource( This query returns data about the top destination IPs. The `limit` parameter controls the amount of records returned. In the following code, the highlighted lines indicate that the query returns the five highest results. -```graphql title="Top N Cards - Destination" {10,22} +```graphql graphql-api-explorer title="Top N Cards - Destination" {10,22} query GetTopNByDestination( $accountTag: string $filter: AccountIpFlows1mGroupsFilter_InputObject @@ -351,10 +358,10 @@ This query extracts the number of TCP packets from the minute-wise rollups of IP Add the following line to the filter to indicate that you want to view TCP data: ```json -{ ipProtocol: 'TCP' } +{ "ipProtocol": "TCP" } ``` -```graphql title="TCP Flags query" +```graphql graphql-api-explorer title="TCP Flags query" query GetTCPFlags( $accountTag: string $filter: AccountIpFlows1mGroupsFilter_InputObject @@ -385,7 +392,7 @@ Use different queries, depending on the time interval you want to examine and wh If the time interval is absolute, for example March 25th 09:00 to March 25th 17:00, then execute a query for attacks within those times. [Use the appropriate query node](#parameters-and-filters), for example `ipFlows1dGroups`, for the time interval. -```graphql title="GetPreviousAttacks query - fetch previous attacks" +```graphql graphql-api-explorer title="GetPreviousAttacks query - fetch previous attacks" query GetPreviousAttacks($accountTag: string, $filter: filter) { viewer { accounts(filter: {accountTag: $accountTag}) { @@ -406,38 +413,38 @@ query GetPreviousAttacks($accountTag: string, $filter: filter) { If the time interval is relative to the current time, for example the last 24 hours or the last 30 minutes, then make a query to the `ipFlows1mGroup` node to check whether there were attacks in the past five minutes. Attacks within the past five minutes are classed as ongoing: the Activity Log displays `Present`. The query response lists the `attackID` values of ongoing attacks. -```graphql title="GetOngoingAttackIds query - check for ongoing attacks" +```graphql graphql-api-explorer title="GetOngoingAttackIds query - check for ongoing attacks" query GetOngoingAttackIds($accountTag: string, $filter: filter) { - viewer { - accounts(filter: { accountTag: $accountTag }) { - ipFlows1mGroups(limit: 1000, filter: $filter) { - dimensions { - attackId - } - } - } - } - } + viewer { + accounts(filter: { accountTag: $accountTag }) { + ipFlows1mGroups(limit: 1000, filter: $filter) { + dimensions { + attackId + } + } + } + } +} ``` If there are ongoing attacks, query the `ipFlows1mAttacksGroups` node, filtering with the `attackID` values from the previous query. The query below returns the maximum bit and packet rates. -```graphql title="GetOngoingAttacks query - fetch data for ongoing attacks" +```graphql graphql-api-explorer title="GetOngoingAttacks query - fetch data for ongoing attacks" query GetOngoingAttacks($accountTag: string, $filter: filter) { - viewer { - accounts(filter: { accountTag: $accountTag }) { - ipFlows1mAttacksGroups(limit: 1000, filter: $filter) { - dimensions { - attackId - } - max { - bitsPerSecond - packetsPerSecond - } - } - } - } - } + viewer { + accounts(filter: { accountTag: $accountTag }) { + ipFlows1mAttacksGroups(limit: 1000, filter: $filter) { + dimensions { + attackId + } + max { + bitsPerSecond + packetsPerSecond + } + } + } + } +} ``` If there are no ongoing attacks, use the `GetPreviousAttacks` query to display data for attacks within an absolute time interval. diff --git a/src/content/docs/api-shield/security/graphql-protection/configure.mdx b/src/content/docs/api-shield/security/graphql-protection/configure.mdx index c021a44d6c6cf06..20a4e333279eccd 100644 --- a/src/content/docs/api-shield/security/graphql-protection/configure.mdx +++ b/src/content/docs/api-shield/security/graphql-protection/configure.mdx @@ -5,7 +5,6 @@ type: overview head: - tag: title content: Configure GraphQL malicious query protection - --- Use the [Cloudflare GraphQL API](/analytics/graphql-api/getting-started/) to gather data about your GraphQL API’s current usage and configure Cloudflare’s GraphQL malicious query protection to log or block malicious queries. @@ -16,14 +15,14 @@ Query size is defined as the number of terminal fields (leaves) in the query, wh ```graphql title="GraphQL query" { - terminalField1 - nonTerminalField1(filter: 123) { - terminalField2 - nonTerminalField2 { - terminalField3 - terminalField4 - } - } + terminalField1 + nonTerminalField1(filter: 123) { + terminalField2 + nonTerminalField2 { + terminalField3 + terminalField4 + } + } } ``` @@ -31,19 +30,30 @@ Query size is defined as the number of terminal fields (leaves) in the query, wh Using the new `apiGatewayGraphqlQueryAnalyticsGroups` node in the Cloudflare GraphQL API, you can retrieve `apiGatewayGraphqlQuerySize` and `apiGatewayGraphqlQueryDepth` dimensions. -```graphql title="GraphQL query" -query ApiGatewayGraphqlQueryAnalytics($zoneTag: string, $datetimeStart: Time, $datetimeEnd: Time) { - viewer { - zones(filter: {zoneTag: $zoneTag}) { - apiGatewayGraphqlQueryAnalyticsGroups(limit: 100, orderBy: [apiGatewayGraphqlQuerySize_DESC, apiGatewayGraphqlQueryDepth_DESC], filter: {datetime_geq:$datetimeStart, datetime_leq:$datetimeEnd}) { - count - dimensions { - apiGatewayGraphqlQuerySize - apiGatewayGraphqlQueryDepth - } - } - } - } +```graphql graphql-api-explorer title="GraphQL query" +query ApiGatewayGraphqlQueryAnalytics( + $zoneTag: string + $start: Time + $end: Time +) { + viewer { + zones(filter: { zoneTag: $zoneTag }) { + apiGatewayGraphqlQueryAnalyticsGroups( + limit: 100 + orderBy: [ + apiGatewayGraphqlQuerySize_DESC + apiGatewayGraphqlQueryDepth_DESC + ] + filter: { datetime_geq: $start, datetime_leq: $end } + ) { + count + dimensions { + apiGatewayGraphqlQuerySize + apiGatewayGraphqlQueryDepth + } + } + } + } } ``` @@ -51,31 +61,31 @@ With the above query, you will get the following response: ```json title="Response" { - "data": { - "viewer": { - "zones": [ - { - "apiGatewayGraphqlQueryAnalyticsGroups": [ - { - "count": 10, - "dimensions": { - "apiGatewayGraphqlQueryDepth": 1, - "apiGatewayGraphqlQuerySize": 11 - } - }, - { - "count": 10, - "dimensions": { - "apiGatewayGraphqlQueryDepth": 1, - "apiGatewayGraphqlQuerySize": 2 - } - } - ] - } - ] - } - }, - "errors": null + "data": { + "viewer": { + "zones": [ + { + "apiGatewayGraphqlQueryAnalyticsGroups": [ + { + "count": 10, + "dimensions": { + "apiGatewayGraphqlQueryDepth": 1, + "apiGatewayGraphqlQuerySize": 11 + } + }, + { + "count": 10, + "dimensions": { + "apiGatewayGraphqlQueryDepth": 1, + "apiGatewayGraphqlQuerySize": 2 + } + } + ] + } + ] + } + }, + "errors": null } ``` @@ -141,8 +151,6 @@ For example, you can deploy the following rule via the API or the dashboard to b :::note - You are not able to configure which endpoints the GraphQL parsing runs on. Requests are parsed if they are targeting a path ending in `/graphql`. - ::: diff --git a/src/content/docs/cloudflare-one/insights/analytics/gateway.mdx b/src/content/docs/cloudflare-one/insights/analytics/gateway.mdx index fff34ee60042549..cb03daaac8262bb 100644 --- a/src/content/docs/cloudflare-one/insights/analytics/gateway.mdx +++ b/src/content/docs/cloudflare-one/insights/analytics/gateway.mdx @@ -38,12 +38,12 @@ To explore the schema, you can use a GraphQL client such as [GraphiQL](https://g 2. In your GraphQL client, [add your API token](/analytics/graphql-api/getting-started/authentication/graphql-client-headers/) as an Authorization header. 3. Compose a query to access your Gateway Analytics datasets. For example, you can query the `gatewayResolverQueriesAdaptiveGroups` dataset to return the adaptive groups of DNS queries resolved by Gateway: - ```graphql - { + ```graphql graphql-api-explorer + query GatewaySampleQuery($accountTag: string!, $start: Time) { viewer { - accounts(filter: { accountTag: "" }) { + accounts(filter: { accountTag: $accountTag }) { gatewayResolverQueriesAdaptiveGroups( - filter: { datetime_gt: "2025-02-28T00:00:00Z" } + filter: { datetime_gt: $start } limit: 10 ) { count diff --git a/src/content/docs/d1/observability/metrics-analytics.mdx b/src/content/docs/d1/observability/metrics-analytics.mdx index 50a0d51971087ea..f498cfe3c96cca7 100644 --- a/src/content/docs/d1/observability/metrics-analytics.mdx +++ b/src/content/docs/d1/observability/metrics-analytics.mdx @@ -61,17 +61,18 @@ D1's GraphQL datasets require an `accountTag` filter with your Cloudflare accoun To query the sum of `readQueries`, `writeQueries` for a given `$databaseId`, grouping by `databaseId` and `date`: -```graphql -query { +```graphql graphql-api-explorer +query D1ObservabilitySampleQuery( + $accountTag: string! + $start: Date + $end: Date + $databaseId: string +) { viewer { - accounts(filter: { accountTag: $accountId }) { + accounts(filter: { accountTag: $accountTag }) { d1AnalyticsAdaptiveGroups( limit: 10000 - filter: { - date_geq: $startDate - date_leq: $endDate - databaseId: $databaseId - } + filter: { date_geq: $start, date_leq: $end, databaseId: $databaseId } orderBy: [date_DESC] ) { sum { @@ -90,17 +91,18 @@ query { To query both the average `queryBatchTimeMs` and the 90th percentile `queryBatchTimeMs` per database: -```graphql -query { +```graphql graphql-api-explorer +query D1ObservabilitySampleQuery2( + $accountTag: string! + $start: Date + $end: Date + $databaseId: string +) { viewer { accounts(filter: { accountTag: $accountId }) { d1AnalyticsAdaptiveGroups( limit: 10000 - filter: { - date_geq: $startDate - date_leq: $endDate - databaseId: $databaseId - } + filter: { date_geq: $start, date_leq: $end, databaseId: $databaseId } orderBy: [date_DESC] ) { quantiles { @@ -118,17 +120,18 @@ query { To query your account-wide `readQueries` and `writeQueries`: -```graphql -query { +```graphql graphql-api-explorer +query D1ObservabilitySampleQuery3( + $accountTag: string! + $start: Date + $end: Date + $databaseId: string +) { viewer { - accounts(filter: { accountTag: $accountId }) { + accounts(filter: { accountTag: $accountTag }) { d1AnalyticsAdaptiveGroups( limit: 10000 - filter: { - date_geq: $startDate - date_leq: $endDate - databaseId: $databaseId - } + filter: { date_geq: $start, date_leq: $end, databaseId: $databaseId } ) { sum { readQueries @@ -168,6 +171,7 @@ Run `wrangler d1 insights --help` to view current options. ```sh npx wrangler d1 insights --sort-type=sum --sort-by=count --limit=3 ``` + ```sh output ⛅️ wrangler 3.95.0 ------------------- @@ -213,6 +217,7 @@ npx wrangler d1 insights --sort-type=sum --sort-by=count --limit } ] ``` +
@@ -220,6 +225,7 @@ npx wrangler d1 insights --sort-type=sum --sort-by=count --limit ```sh npx wrangler d1 insights --sort-type=avg --sort-by=time --limit=3 ``` + ```sh output ⛅️ wrangler 3.95.0 ------------------- @@ -265,6 +271,7 @@ npx wrangler d1 insights --sort-type=avg --sort-by=time --limit= } ] ``` +
@@ -272,6 +279,7 @@ npx wrangler d1 insights --sort-type=avg --sort-by=time --limit= ```sh npx wrangler d1 insights --sort-type=sum --sort-by=writes --limit=10 --timePeriod=7d ``` + ```sh output ⛅️ wrangler 3.95.0 ------------------- @@ -317,10 +325,11 @@ npx wrangler d1 insights --sort-type=sum --sort-by=writes --limi } ] ``` +
:::note The quantity `queryEfficiency` measures how efficient your query was. It is calculated as: the number of rows returned divided by the number of rows read. Generally, you should try to get `queryEfficiency` as close to `1` as possible. Refer to [Use indexes](/d1/best-practices/use-indexes/) for more information on efficient querying. -::: \ No newline at end of file +::: diff --git a/src/content/docs/hyperdrive/observability/metrics.mdx b/src/content/docs/hyperdrive/observability/metrics.mdx index 3fafc960f42213f..792dfca99da1b03 100644 --- a/src/content/docs/hyperdrive/observability/metrics.mdx +++ b/src/content/docs/hyperdrive/observability/metrics.mdx @@ -3,7 +3,6 @@ pcx_content_type: concept title: Metrics and analytics sidebar: order: 20 - --- Hyperdrive exposes analytics that allow you to inspect query volume, query latency and cache ratios size across all and/or each Hyperdrive configuration in your account. @@ -17,9 +16,9 @@ Hyperdrive currently exports the below metrics as part of the `hyperdriveQueries | Queries | `count` | The number of queries issued against your Hyperdrive in the given time period. | | Cache Status | `cacheStatus` | Whether the query was cached or not. Can be one of `disabled`, `hit`, `miss`, `uncacheable`, `multiplestatements`, `notaquery`, `oversizedquery`, `oversizedresult`, `parseerror`, `transaction`, and `volatile`. | | Query Bytes | `queryBytes` | The size of your queries, in bytes. | -| Result Bytes | `resultBytes` | The size of your query *results*, in bytes. | -| Connection Latency | `connectionLatency` | The time (in milliseconds) required to establish new connections from Hyperdrive to your database, as measured from your Hyperdrive connection pool(s). | -| Query Latency | `queryLatency` | The time (in milliseconds) required to query (and receive results) from your database, as measured from your Hyperdrive connection pool(s). | +| Result Bytes | `resultBytes` | The size of your query _results_, in bytes. | +| Connection Latency | `connectionLatency` | The time (in milliseconds) required to establish new connections from Hyperdrive to your database, as measured from your Hyperdrive connection pool(s). | +| Query Latency | `queryLatency` | The time (in milliseconds) required to query (and receive results) from your database, as measured from your Hyperdrive connection pool(s). | | Event Status | `eventStatus` | Whether a query responded successfully (`complete`) or failed (`error`). | Metrics can be queried (and are retained) for the past 31 days. @@ -47,73 +46,88 @@ Examples of how to explore your Hyperdrive metrics. ### Get the number of queries handled via your Hyperdrive config by cache status -```graphql -query HyperdriveQueries($accountTag: string!, $configId: string!, $datetimeStart: Time!, $datetimeEnd: Time!) { - viewer { - accounts(filter: {accountTag: $accountTag}) { - hyperdriveQueriesAdaptiveGroups( - limit: 10000 - filter: { - configId: $configId - datetime_geq: $datetimeStart - datetime_leq: $datetimeEnd - } - ) { - count - dimensions { - cacheStatus - } - } - } - } +```graphql graphql-api-explorer +query HyperdriveQueries( + $accountTag: string! + $configId: string! + $datetimeStart: Time! + $datetimeEnd: Time! +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + hyperdriveQueriesAdaptiveGroups( + limit: 10000 + filter: { + configId: $configId + datetime_geq: $datetimeStart + datetime_leq: $datetimeEnd + } + ) { + count + dimensions { + cacheStatus + } + } + } + } } ``` ### Get the average query and connection latency for queries handled via your Hyperdrive config within a range of time, excluding queries that failed due to an error -```graphql -query AverageHyperdriveLatencies($accountTag: string!, $configId: string!, $datetimeStart: Time!, $datetimeEnd: Time!) { - viewer { - accounts(filter: {accountTag: $accountTag}) { - hyperdriveQueriesAdaptiveGroups( - limit: 10000 - filter: { - configId: $configId - eventStatus: "complete" - datetime_geq: $datetimeStart - datetime_leq: $datetimeEnd - } - ) { - avg { - connectionLatency - queryLatency - } - } - } - } +```graphql graphql-api-explorer +query AverageHyperdriveLatencies( + $accountTag: string! + $configId: string! + $datetimeStart: Time! + $datetimeEnd: Time! +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + hyperdriveQueriesAdaptiveGroups( + limit: 10000 + filter: { + configId: $configId + eventStatus: "complete" + datetime_geq: $datetimeStart + datetime_leq: $datetimeEnd + } + ) { + avg { + connectionLatency + queryLatency + } + } + } + } } ``` ### Get the total amount of query and result bytes flowing through your Hyperdrive config -```graphql -query HyperdriveQueryAndResultBytesForSuccessfulQueries($accountTag: string!, $configId: string!, $datetimeStart: Date!, $datetimeEnd: Date!) { - viewer { - accounts(filter: {accountTag: $accountTag}) { - hyperdriveQueriesAdaptiveGroups( - limit: 10000 - filter: { - configId: $configId - datetime_geq: $datetimeStart - datetime_leq: $datetimeEnd - } - ) { - sum { - queryBytes - resultBytes - } - } - } - } +```graphql graphql-api-explorer +query HyperdriveQueryAndResultBytesForSuccessfulQueries( + $accountTag: string! + $configId: string! + $datetimeStart: Date! + $datetimeEnd: Date! +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + hyperdriveQueriesAdaptiveGroups( + limit: 10000 + filter: { + configId: $configId + datetime_geq: $datetimeStart + datetime_leq: $datetimeEnd + } + ) { + sum { + queryBytes + resultBytes + } + } + } + } } ``` diff --git a/src/content/docs/kv/observability/metrics-analytics.mdx b/src/content/docs/kv/observability/metrics-analytics.mdx index c9836237512a402..2d5ff25a380fae0 100644 --- a/src/content/docs/kv/observability/metrics-analytics.mdx +++ b/src/content/docs/kv/observability/metrics-analytics.mdx @@ -3,7 +3,6 @@ pcx_content_type: concept title: Metrics and analytics sidebar: order: 10 - --- KV exposes analytics that allow you to inspect requests and storage across all namespaces in your account. @@ -14,10 +13,10 @@ The metrics displayed in the [Cloudflare dashboard](https://dash.cloudflare.com/ KV currently exposes the below metrics: -| Dataset | GraphQL Dataset Name | Description | -| ----------------------- | --------------------------- | ------------------------------------------------------------- | -| Operations | `kvOperationsAdaptiveGroups`| This dataset consists of the operations made to your KV namespaces. | -| Storage | `kvStorageAdaptiveGroups` | This dataset consists of the storage details of your KV namespaces. | +| Dataset | GraphQL Dataset Name | Description | +| ---------- | ---------------------------- | ------------------------------------------------------------------- | +| Operations | `kvOperationsAdaptiveGroups` | This dataset consists of the operations made to your KV namespaces. | +| Storage | `kvStorageAdaptiveGroups` | This dataset consists of the storage details of your KV namespaces. | Metrics can be queried (and are retained) for the past 31 days. @@ -49,86 +48,103 @@ The following are common GraphQL queries that you can use to retrieve informatio ```json { - "accountTag":"", - "namespaceId": "", - "date_geq": "2024-07-15", - "date_leq": "2024-07-30" + "accountTag": "", + "namespaceId": "", + "date_geq": "2024-07-15", + "date_leq": "2024-07-30" } ``` #### Operations -To query the sum of read, write, delete, and list operations for a given `namespaceId` and for a given date range (`date_geq` and `date_leq`), grouped by `date` and `actionType`: - -```graphql -query { - viewer { - accounts(filter: { accountTag: $accountTag }) { - kvOperationsAdaptiveGroups( - filter: { namespaceId: $namespaceId, date_geq: $date_geq, date_leq: $date_leq } - limit: 10000 +To query the sum of read, write, delete, and list operations for a given `namespaceId` and for a given date range (`start` and `end`), grouped by `date` and `actionType`: + +```graphql graphql-api-explorer +query KvOperationsSample( + $accountTag: string! + $namespaceId: string + $start: Date + $end: Date +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + kvOperationsAdaptiveGroups( + filter: { namespaceId: $namespaceId, date_geq: $start, date_leq: $end } + limit: 10000 orderBy: [date_DESC] - ) { - sum { - requests - } - dimensions { - date - actionType - } - } - } - } + ) { + sum { + requests + } + dimensions { + date + actionType + } + } + } + } } ``` - -To query the distribution of the latency for read operations for a given `namespaceId` within a given date range (`date_geq`, `date_leq`): - -```graphql -query { - viewer { - accounts(filter: { accountTag: $accountTag }) { - kvOperationsAdaptiveGroups( - filter: { namespaceId: $namespaceId, date_geq: $date_geq, date_leq: $date_leq, actionType: "read" } - limit: 10000 - ) { - sum { - requests - } - dimensions { - actionType - } - quantiles { - latencyMsP25 - latencyMsP50 - latencyMsP75 - latencyMsP90 - latencyMsP99 - latencyMsP999 - } - } - } - } +To query the distribution of the latency for read operations for a given `namespaceId` within a given date range (`start`, `end`): + +```graphql graphql-api-explorer +query KvOperationsSample2( + $accountTag: string! + $namespaceId: string + $start: Date + $end: Date +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + kvOperationsAdaptiveGroups( + filter: { + namespaceId: $namespaceId + date_geq: $start + date_leq: $end + actionType: "read" + } + limit: 10000 + ) { + sum { + requests + } + dimensions { + actionType + } + quantiles { + latencyMsP25 + latencyMsP50 + latencyMsP75 + latencyMsP90 + latencyMsP99 + latencyMsP999 + } + } + } + } } ``` To query your account-wide read, write, delete, and list operations across all KV namespaces: -```graphql -query { - viewer { - accounts(filter: { accountTag: $accountTag }) { - kvOperationsAdaptiveGroups(filter: { date_geq: $date_geq, date_leq: $date_leq }, limit: 10000) { - sum { - requests - } - dimensions { - actionType - } - } - } - } +```graphql graphql-api-explorer +query KvOperationsAllSample($accountTag: string!, $start: Date, $end: Date) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + kvOperationsAdaptiveGroups( + filter: { date_geq: $start, date_leq: $end } + limit: 10000 + ) { + sum { + requests + } + dimensions { + actionType + } + } + } + } } ``` @@ -136,24 +152,29 @@ query { To query the storage details (`keyCount` and `byteCount`) of a KV namespace for every day of a given date range: -```graphql -query Viewer { - viewer { - accounts(filter: { accountTag: $accountTag }) { - kvStorageAdaptiveGroups( - filter: { date_geq: $date_geq, date_leq: $date_leq, namespaceId: $namespaceId } - limit: 10000 - orderBy: [date_DESC] - ) { - max { - keyCount - byteCount - } - dimensions { - date - } - } - } - } +```graphql graphql-api-explorer +query Viewer( + $accountTag: string! + $namespaceId: string + $start: Date + $end: Date +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + kvStorageAdaptiveGroups( + filter: { date_geq: $start, date_leq: $end, namespaceId: $namespaceId } + limit: 10000 + orderBy: [date_DESC] + ) { + max { + keyCount + byteCount + } + dimensions { + date + } + } + } + } } -``` \ No newline at end of file +``` diff --git a/src/content/docs/load-balancing/reference/load-balancing-analytics.mdx b/src/content/docs/load-balancing/reference/load-balancing-analytics.mdx index 82b62216bc411b9..7709103b09d1e85 100644 --- a/src/content/docs/load-balancing/reference/load-balancing-analytics.mdx +++ b/src/content/docs/load-balancing/reference/load-balancing-analytics.mdx @@ -8,23 +8,20 @@ head: content: Load balancing analytics description: Use load balancing analytics to evaluate traffic flow, assess the health of endpoints, and review health changes over time. - --- -import { Details } from "~/components" +import { Details } from "~/components"; Using load balancing analytics, you can: -* Evaluate traffic flow. -* Assess the health status of endpoints in your pools. -* Review changes in pools and pool health over time. +- Evaluate traffic flow. +- Assess the health status of endpoints in your pools. +- Review changes in pools and pool health over time. :::note - Load balancing analytics are only available to customers on paid plans (Pro, Business, and Enterprise). - ::: ## Dashboard Analytics @@ -35,18 +32,16 @@ To view **Overview** metrics for your load balancer, go to **Traffic** > **Load These metrics show the number of requests routed to specific pools within a load balancer, helping you: -* Evaluate the effects of adding or removing a pool. -* Decide when to create new pools. -* Plan for peak traffic demands and future infrastructure needs. +- Evaluate the effects of adding or removing a pool. +- Decide when to create new pools. +- Plan for peak traffic demands and future infrastructure needs. Add additional filters for specific pools, times, regions, and endpoints. :::note - Load balancing requests are the number of uncached requests made by your load balancer. By default, Cloudflare caches resolved IP addresses for up to five seconds. - ::: ### Latency @@ -67,33 +62,32 @@ For more flexibility, get load balancing metrics directly from the [GraphQL Anal Get started with a sample query: -
This query shows the number of requests each pool receives from each location in Cloudflare's global network. -```graphql title="Query" -{ - viewer { - zones(filter: {zoneTag: "your Zone ID"}) { - loadBalancingRequestsAdaptiveGroups( - limit: 100, - filter: { - datetime_geq: "2021-06-26T00:00:00Z", - datetime_leq: "2021-06-26T03:00:00Z", - lbName:"lb.example.com" - }, - orderBy: [datetimeFifteenMinutes_DESC] - ) { - count - dimensions { - datetimeFifteenMinutes - coloCode - selectedPoolName - } - } - } - } +```graphql graphql-api-explorer title="Query" +query RequestsPerPool($zoneTag: string, $start: Time, $end: Time) { + viewer { + zones(filter: { zoneTag: $zoneTag }) { + loadBalancingRequestsAdaptiveGroups( + limit: 100 + filter: { + datetime_geq: $start + datetime_leq: $end + lbName: "lb.example.com" + } + orderBy: [datetimeFifteenMinutes_DESC] + ) { + count + dimensions { + datetimeFifteenMinutes + coloCode + selectedPoolName + } + } + } + } } ``` @@ -121,10 +115,8 @@ This query shows the number of requests each pool receives from each location in } ``` -
-
This query shows the weighted, round-trip time (RTT) measurement (`avgRttMs`) for monitor requests from a specific data center (for example, Singapore or `SIN`) to each pool in a specific load balancer. @@ -134,30 +126,30 @@ This query shows the weighted, round-trip time (RTT) measurement (`avgRttMs`) fo Note that `avgRttMs` refers to the round-trip time that is measured by the monitors and used in steering decisions. `avgRttMs` is different from the raw RTT for individual requests that reach the Cloudflare network. ::: -```graphql title="Query" -{ - viewer { - zones(filter: {zoneTag: "your Zone ID"}) { - loadBalancingRequestsAdaptive( - limit: 100, - filter: { - datetime_geq: "2021-06-26T00:00:00Z", - datetime_leq: "2021-06-26T03:00:00Z", - lbName:"lb.example.com", - coloCode: "SIN" - }, - orderBy: [datetime_DESC] - ) { - selectedPoolName - pools { - poolName - healthy - healthCheckEnabled - avgRttMs - } - } - } - } +```graphql graphql-api-explorer title="Query" +query RequestsPerDataCenter($zoneTag: string, $start: Time, $end: Time) { + viewer { + zones(filter: { zoneTag: $zoneTag }) { + loadBalancingRequestsAdaptive( + limit: 100 + filter: { + datetime_geq: $start + datetime_leq: $end + lbName: "lb.example.com" + coloCode: "SIN" + } + orderBy: [datetime_DESC] + ) { + selectedPoolName + pools { + poolName + healthy + healthCheckEnabled + avgRttMs + } + } + } + } } ``` @@ -200,5 +192,4 @@ Note that `avgRttMs` refers to the round-trip time that is measured by the monit } ``` -
diff --git a/src/content/docs/magic-firewall/tutorials/graphql-analytics.mdx b/src/content/docs/magic-firewall/tutorials/graphql-analytics.mdx index 35dea13ad7c0d06..bafb4cfbc16eba6 100644 --- a/src/content/docs/magic-firewall/tutorials/graphql-analytics.mdx +++ b/src/content/docs/magic-firewall/tutorials/graphql-analytics.mdx @@ -41,27 +41,26 @@ In this section, you will run a test query to retrieve a five minute count of al For additional information about the Analytics schema, refer to [Explore the Analytics schema with GraphiQL](/analytics/graphql-api/getting-started/explore-graphql-schema/). -```graphql -query { - viewer { - accounts(filter: {accountTag: ""}) { - magicFirewallSamplesAdaptiveGroups( - filter: {datetime_geq: "2022-01-05T11:00:00Z", - datetime_leq: "2022-01-05T12:00:00Z"}, - limit: 2, - orderBy: [datetimeFiveMinute_DESC]) - { - sum { - bits - packets - } - dimensions { - datetimeFiveMinute - ruleId - } - } - } - } +```graphql graphql-api-explorer +query MagicFirewallExample($accountTag: string!, $start: Time, $end: Time) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + magicFirewallSamplesAdaptiveGroups( + filter: { datetime_geq: $start, datetime_leq: $end } + limit: 2 + orderBy: [datetimeFiveMinute_DESC] + ) { + sum { + bits + packets + } + dimensions { + datetimeFiveMinute + ruleId + } + } + } + } } ``` @@ -73,37 +72,38 @@ Use the example below to display the total number of packets and bits for the to For each stream, display the: -* Source and destination IP addresses -* Ingress Cloudflare data centers that received it -* Total traffic volume in bits and packets received within the hour -* Actions taken by the firewall rule - -```graphql -query{ - viewer { - accounts(filter: {accountTag: ""}) { - magicFirewallNetworkAnalyticsAdaptiveGroups( - filter: { - ruleId: "", - datetime_geq: "2022-01-12T10:00:00Z", - datetime_leq: "2022-01-12T11:00:00Z" - } - limit: 10, - orderBy: [avg_packetRateFiveMinutes_DESC]) - { - sum { - bits - packets - } - dimensions { - coloCity - ipDestinationAddress - ipSourceAddress - outcome - } - } - } -} +- Source and destination IP addresses +- Ingress Cloudflare data centers that received it +- Total traffic volume in bits and packets received within the hour +- Actions taken by the firewall rule + +```graphql graphql-api-explorer +query MagicFirewallObtainRules( + $accountId: string! + $ruleId: string + $start: Time + $end: Time +) { + viewer { + accounts(filter: { accountTag: $accountId }) { + magicFirewallNetworkAnalyticsAdaptiveGroups( + filter: { ruleId: $ruleId, datetime_geq: $start, datetime_leq: $end } + limit: 10 + orderBy: [avg_packetRateFiveMinutes_DESC] + ) { + sum { + bits + packets + } + dimensions { + coloCity + ipDestinationAddress + ipSourceAddress + outcome + } + } + } + } } ``` @@ -115,65 +115,62 @@ By setting `verdict` to `drop` and `outcome` as `pass`, we are filtering for tra For each stream, display the: -* Source and destination IP addresses. -* Ingress Cloudflare data centers that received it. -* Total traffic volume in bits and packets received within the hour. - -```graphql -query{ - viewer { - accounts(filter: {accountTag: ""}) { - magicIDPSNetworkAnalyticsAdaptiveGroups( - filter: { - datetime_geq: "2022-01-12T10:00:00Z", - datetime_leq: "2022-01-12T11:00:00Z", - verdict: drop, - outcome: pass - } - limit: 10, - orderBy: [avg_packetRateFiveMinutes_DESC]) - { - sum { - bits - packets - } - dimensions { - coloCity - ipDestinationAddress - ipSourceAddress - } - } - } -} +- Source and destination IP addresses. +- Ingress Cloudflare data centers that received it. +- Total traffic volume in bits and packets received within the hour. + +```graphql graphql-api-explorer +query MagicFirewallObtainIDS($accountTag: string!, $start: Time, $end: Time) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + magicIDPSNetworkAnalyticsAdaptiveGroups( + filter: { + datetime_geq: $start + datetime_leq: $end + verdict: drop + outcome: pass + } + limit: 10 + orderBy: [avg_packetRateFiveMinutes_DESC] + ) { + sum { + bits + packets + } + dimensions { + coloCity + ipDestinationAddress + ipSourceAddress + } + } + } + } } ``` Alternatively, to inspect all traffic that was analyzed, but grouped into malicious traffic and other traffic, the example below can be used. The response will contain two entries for each five minute timestamp. `verdict` will be set to `drop` for malicious traffic, and `verdict` will be set to `pass` for traffic that did not match any of the IDS rules. -```graphql -query{ - viewer { - accounts(filter: {accountTag: ""}) { - magicIDPSNetworkAnalyticsAdaptiveGroups( - filter: { - datetime_geq: "2022-01-12T10:00:00Z", - datetime_leq: "2022-01-12T11:00:00Z" - } - limit: 10, - orderBy: [avg_packetRateFiveMinutes_DESC]) - { - sum { - bits - packets - } - dimensions { - coloCity - ipDestinationAddress - ipSourceAddress - verdict - } - } - } -} +```graphql graphql-api-explorer +query MagicFirewallTraffic($accountTag: string!, $start: Time, $end: Time) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + magicIDPSNetworkAnalyticsAdaptiveGroups( + filter: { datetime_geq: $start, datetime_leq: $end } + limit: 10 + orderBy: [avg_packetRateFiveMinutes_DESC] + ) { + sum { + bits + packets + } + dimensions { + coloCity + ipDestinationAddress + ipSourceAddress + verdict + } + } + } + } } ``` diff --git a/src/content/docs/magic-network-monitoring/tutorials/graphql-analytics.mdx b/src/content/docs/magic-network-monitoring/tutorials/graphql-analytics.mdx index 9bfa5f0ba904565..922fa517bdc71b0 100644 --- a/src/content/docs/magic-network-monitoring/tutorials/graphql-analytics.mdx +++ b/src/content/docs/magic-network-monitoring/tutorials/graphql-analytics.mdx @@ -9,10 +9,9 @@ sidebar: head: - tag: title content: GraphQL Analytics - --- -import { GlossaryTooltip } from "~/components" +import { GlossaryTooltip } from "~/components"; Use the GraphQL Analytics API to retrieve Magic Network Monitoring flow data. @@ -31,25 +30,24 @@ In this section, you will run a test query to retrieve a five minute sum of bits For additional information about the Analytics schema, refer to [Explore the Analytics schema with GraphiQL](/analytics/graphql-api/getting-started/explore-graphql-schema/). -```graphql - query { - viewer { - accounts(filter: { accountTag: "ACCOUNT_ID" }) { - mnmFlowDataAdaptiveGroups( - filter: {datetime_gt: "2022-12-01T00:00:00Z", - datetime_leq: "2022-12-02T00:00:00Z"}, - limit: 10 - orderBy: [datetimeFiveMinutes_DESC] - ) { - sum { - bits - packets - } - dimensions { - datetimeFiveMinutes - } - } - } - } - } +```graphql graphql-api-explorer +query MagicNetworkMonitoring($accountTag: string!, $start: Time, $end: Time) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + mnmFlowDataAdaptiveGroups( + filter: { datetime_gt: $start, datetime_leq: $end } + limit: 10 + orderBy: [datetimeFiveMinutes_DESC] + ) { + sum { + bits + packets + } + dimensions { + datetimeFiveMinutes + } + } + } + } +} ``` diff --git a/src/content/docs/magic-wan/configuration/connector/device-metrics.mdx b/src/content/docs/magic-wan/configuration/connector/device-metrics.mdx index 44801318093165e..c5b99e34861404c 100644 --- a/src/content/docs/magic-wan/configuration/connector/device-metrics.mdx +++ b/src/content/docs/magic-wan/configuration/connector/device-metrics.mdx @@ -3,7 +3,6 @@ pcx_content_type: how-to title: Device metrics sidebar: order: 8 - --- Cloudflare customers can inspect metrics for a specific Magic WAN Connector in the Cloudflare dashboard. The Magic WAN Connector device metrics measured by Cloudflare include: @@ -26,36 +25,40 @@ Customers can query Cloudflare's GraphQL API to fetch their Magic WAN Connector For example: -```graphql -query GetResults($accountTag: string, $datetimeStart: string, $datetimeEnd: string) { - viewer { - accounts(filter: {accountTag: $accountTag}) { - MagicWANConnectorMetricsAdaptiveGroups( - limit: 100, - filter: { - mconnInterfaceType: "system", - datetime_geq: $datetimeStart, - datetime_lt: $datetimeEnd, - } - ){ - avg { - cpuTemperature - cpuLoadPercentage - diskUsagePercentage - memoryUsagePercentage - } - dimensions { - mconnInterfaceName - } - } - } - } +```graphql graphql-api-explorer +query MagicWanDeviceMetrics( + $accountTag: string! + $datetimeStart: Time + $datetimeEnd: Time +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + MagicWANConnectorMetricsAdaptiveGroups( + limit: 100 + filter: { + mconnInterfaceType: "system" + datetime_geq: $datetimeStart + datetime_lt: $datetimeEnd + } + ) { + avg { + cpuTemperature + cpuLoadPercentage + diskUsagePercentage + memoryUsagePercentage + } + dimensions { + mconnInterfaceName + } + } + } + } } ``` ### Average CPU load explained -The metric `average CPU load` is unique and distinctly different from `CPU utilization` which is another common CPU metric. The Magic WAN connector uses a [Unix-style CPU load calculation](https://en.wikipedia.org/wiki/Load_\(computing\)). +The metric `average CPU load` is unique and distinctly different from `CPU utilization` which is another common CPU metric. The Magic WAN connector uses a [Unix-style CPU load calculation](). CPU load is a measure of the number of processes that are currently running and that are waiting to be run on the CPU. Cloudflare collects the one minute load average from the device and converts that into a percentage based on the total number of cores in the CPU. If the Magic WAN Connector CPU has eight cores, and a one minute load average of two, then the average CPU load is 25%. If the average CPU load is above 100%, then there are processes in the queue that are waiting to be executed on the CPU. diff --git a/src/content/docs/page-shield/policies/violations.mdx b/src/content/docs/page-shield/policies/violations.mdx index 187388d160abf28..0e0e3945a8284af 100644 --- a/src/content/docs/page-shield/policies/violations.mdx +++ b/src/content/docs/page-shield/policies/violations.mdx @@ -38,11 +38,11 @@ For an introduction to GraphQL querying, refer to [Querying basics](/analytics/g ### Example -```graphql title="Example GraphQL query" +```graphql graphql-api-explorer title="Example GraphQL query" query PageShieldReports( $zoneTag: string - $datetimeStart: string - $datetimeEnd: string + $datetimeStart: Time + $datetimeEnd: Time ) { viewer { zones(filter: { zoneTag: $zoneTag }) { diff --git a/src/content/docs/pipelines/observability/metrics.mdx b/src/content/docs/pipelines/observability/metrics.mdx index 6d96763ea0af66e..630bdc3b3a8b201 100644 --- a/src/content/docs/pipelines/observability/metrics.mdx +++ b/src/content/docs/pipelines/observability/metrics.mdx @@ -3,7 +3,6 @@ pcx_content_type: concept title: Metrics and analytics sidebar: order: 10 - --- Pipelines expose metrics which allow you to measure data ingested, requests made, and data delivered. @@ -11,37 +10,41 @@ Pipelines expose metrics which allow you to measure data ingested, requests made The metrics displayed in the [Cloudflare dashboard](https://dash.cloudflare.com/) are queried from Cloudflare’s [GraphQL Analytics API](/analytics/graphql-api/). You can access the metrics [programmatically](#query-via-the-graphql-api) via GraphQL or HTTP client. ## Metrics + ### Ingestion + Pipelines export the below metrics within the `pipelinesIngestionAdaptiveGroups` dataset. -| Metric | GraphQL Field Name | Description | -| ---------------------- | ------------------------- | ---------------------------------------------------------------| -| Ingestion Events | `count` | Number of ingestion events, or requests made, to a pipeline. | -| Ingested Bytes | `ingestedBytes` | Total number of bytes ingested | -| Ingested Records | `ingestedRecords` | Total number of records ingested | +| Metric | GraphQL Field Name | Description | +| ---------------- | ------------------ | ------------------------------------------------------------ | +| Ingestion Events | `count` | Number of ingestion events, or requests made, to a pipeline. | +| Ingested Bytes | `ingestedBytes` | Total number of bytes ingested | +| Ingested Records | `ingestedRecords` | Total number of records ingested | The `pipelinesIngestionAdaptiveGroups` dataset provides the following dimensions for filtering and grouping queries: -* `pipelineId` - ID of the pipeline -* `datetime` - Timestamp of the ingestion event -* `date` - Timestamp of the ingestion event, truncated to the start of a day -* `datetimeHour` - Timestamp of the ingestion event, truncated to the start of an hour -* `datetimeMinute` - Timestamp of the ingestion event, truncated to the start of a minute + +- `pipelineId` - ID of the pipeline +- `datetime` - Timestamp of the ingestion event +- `date` - Timestamp of the ingestion event, truncated to the start of a day +- `datetimeHour` - Timestamp of the ingestion event, truncated to the start of an hour +- `datetimeMinute` - Timestamp of the ingestion event, truncated to the start of a minute ### Delivery + Pipelines export the below metrics within the `pipelinesDeliveryAdaptiveGroups` dataset. -| Metric | GraphQL Field Name | Description | -| ---------------------- | ------------------------- | ---------------------------------------------------------------| -| Ingestion Events | `count` | Number of delivery events to an R2 bucket | -| Delivered Bytes | `deliveredBytes` | Total number of bytes ingested | +| Metric | GraphQL Field Name | Description | +| ---------------- | ------------------ | ----------------------------------------- | +| Ingestion Events | `count` | Number of delivery events to an R2 bucket | +| Delivered Bytes | `deliveredBytes` | Total number of bytes ingested | The `pipelinesDeliverynAdaptiveGroups` dataset provides the following dimensions for filtering and grouping queries: -* `pipelineId` - ID of the pipeline -* `datetime` - Timestamp of the delivery event -* `date` - Timestamp of the delivery event, truncated to the start of a day -* `datetimeHour` - Timestamp of the delivery event, truncated to the start of an hour -* `datetimeMinute` - Timestamp of the delivery event, truncated to the start of a minute +- `pipelineId` - ID of the pipeline +- `datetime` - Timestamp of the delivery event +- `date` - Timestamp of the delivery event, truncated to the start of a day +- `datetimeHour` - Timestamp of the delivery event, truncated to the start of an hour +- `datetimeMinute` - Timestamp of the delivery event, truncated to the start of a minute ## Query via the GraphQL API @@ -51,49 +54,57 @@ Pipelines GraphQL datasets require an `accountTag` filter with your Cloudflare a ### Measure total bytes & records ingested over time period -```graphql -query PipelineIngestion($accountTag: string!, $pipelineId: string!, $datetimeStart: Time!, $datetimeEnd: Time!) { - viewer { - accounts(filter: {accountTag: $accountTag}) { - pipelinesIngestionAdaptiveGroups( - limit: 10000 - filter: { - pipelineId: $pipelineId - datetime_geq: $datetimeStart - datetime_leq: $datetimeEnd - } - - ) - { - sum { - ingestedBytes, - ingestedRecords, - } - } - } - } +```graphql graphql-api-explorer +query PipelineIngestion( + $accountTag: string! + $pipelineId: string! + $datetimeStart: Time! + $datetimeEnd: Time! +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + pipelinesIngestionAdaptiveGroups( + limit: 10000 + filter: { + pipelineId: $pipelineId + datetime_geq: $datetimeStart + datetime_leq: $datetimeEnd + } + ) { + sum { + ingestedBytes + ingestedRecords + } + } + } + } } ``` ### Measure volume of data delivered -```graphql -query PipelineDelivery($accountTag: string!, $pipelineId: string!, $datetimeStart: Time!, $datetimeEnd: Time!) { - viewer { - accounts(filter: {accountTag: $accountTag}) { - pipelinesDeliveryAdaptiveGroups( - limit: 10000 - filter: { - pipelineId: $pipelineId - datetime_geq: $datetimeStart - datetime_leq: $datetimeEnd - } - ) { - sum { - deliveredBytes, - } - } - } - } +```graphql graphql-api-explorer +query PipelineDelivery( + $accountTag: string! + $pipelineId: string! + $datetimeStart: Time! + $datetimeEnd: Time! +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + pipelinesDeliveryAdaptiveGroups( + limit: 10000 + filter: { + pipelineId: $pipelineId + datetime_geq: $datetimeStart + datetime_leq: $datetimeEnd + } + ) { + sum { + deliveredBytes + } + } + } + } } -``` \ No newline at end of file +``` diff --git a/src/content/docs/queues/observability/metrics.mdx b/src/content/docs/queues/observability/metrics.mdx index 990c2dab542bb0d..dfa7cf8717e86b0 100644 --- a/src/content/docs/queues/observability/metrics.mdx +++ b/src/content/docs/queues/observability/metrics.mdx @@ -3,7 +3,6 @@ pcx_content_type: concept title: Metrics sidebar: order: 20 - --- Queues expose metrics which allow you to measure the queue backlog, consumer concurrency, and message operations. @@ -11,133 +10,155 @@ Queues expose metrics which allow you to measure the queue backlog, consumer con The metrics displayed in the [Cloudflare dashboard](https://dash.cloudflare.com/) are queried from Cloudflare’s [GraphQL Analytics API](/analytics/graphql-api/). You can access the metrics [programmatically](#query-via-the-graphql-api) via GraphQL or HTTP client. ## Metrics + ### Backlog + Queues export the below metrics within the `queuesBacklogAdaptiveGroups` dataset. -| Metric | GraphQL Field Name | Description | -| ---------------------- | ------------------------- | ---------------------------------------------------------------| -| Backlog bytes | `bytes` | Average size of the backlog, in bytes | -| Backlog messages | `messages` | Average size of the backlog, in number of messages | +| Metric | GraphQL Field Name | Description | +| ---------------- | ------------------ | -------------------------------------------------- | +| Backlog bytes | `bytes` | Average size of the backlog, in bytes | +| Backlog messages | `messages` | Average size of the backlog, in number of messages | The `queuesBacklogAdaptiveGroups` dataset provides the following dimensions for filtering and grouping queries: -* `queueID` - ID of the queue -* `datetime` - Timestamp for when the message was sent -* `date` - Timestamp for when the message was sent, truncated to the start of a day -* `datetimeHour` - Timestamp for when the message was sent, truncated to the start of an hour -* `datetimeMinute` - Timestamp for when the message was sent, truncated to the start of a minute + +- `queueID` - ID of the queue +- `datetime` - Timestamp for when the message was sent +- `date` - Timestamp for when the message was sent, truncated to the start of a day +- `datetimeHour` - Timestamp for when the message was sent, truncated to the start of an hour +- `datetimeMinute` - Timestamp for when the message was sent, truncated to the start of a minute ### Consumer concurrency + Queues export the below metrics within the `queueConsumerMetricsAdaptiveGroups` dataset. -| Metric | GraphQL Field Name | Description | -| ---------------------- | ------------------------- | --------------------------------------------------------------- | -| Avg. Consumer Concurrency | `concurrency` | Average number of concurrent consumers over the period | +| Metric | GraphQL Field Name | Description | +| ------------------------- | ------------------ | ------------------------------------------------------ | +| Avg. Consumer Concurrency | `concurrency` | Average number of concurrent consumers over the period | The `queueConsumerMetricsAdaptiveGroups` dataset provides the following dimensions for filtering and grouping queries: -* `queueID` - ID of the queue -* `datetime` - Timestamp for the consumer metrics -* `date` - Timestamp for the consumer metrics, truncated to the start of a day -* `datetimeHour` - Timestamp for the consumer metrics, truncated to the start of an hour -* `datetimeMinute` - Timestamp for the consumer metrics, truncated to the start of a minute + +- `queueID` - ID of the queue +- `datetime` - Timestamp for the consumer metrics +- `date` - Timestamp for the consumer metrics, truncated to the start of a day +- `datetimeHour` - Timestamp for the consumer metrics, truncated to the start of an hour +- `datetimeMinute` - Timestamp for the consumer metrics, truncated to the start of a minute ### Message operations + Queues export the below metrics within the `queueMessageOperationsAdaptiveGroups` dataset. -| Metric | GraphQL Field Name | Description | -| ---------------------- | ------------------------- | --------------------------------------------------------------- | -| Total billable operations | `billableOperations` | Sum of billable operations (writes, reads, and deletes) over the time period | -| Total Bytes | `bytes` | Sum of bytes read, written, and deleted from the queue | -| Lag | `lagTime` | Average lag time in milliseconds between when the message was written and the operation to consume the message. | -| Retries | `retryCount` | Average number of retries per message | -| Message Size | `messageSize` | Maximum message size over the specified period | +| Metric | GraphQL Field Name | Description | +| ------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------- | +| Total billable operations | `billableOperations` | Sum of billable operations (writes, reads, and deletes) over the time period | +| Total Bytes | `bytes` | Sum of bytes read, written, and deleted from the queue | +| Lag | `lagTime` | Average lag time in milliseconds between when the message was written and the operation to consume the message. | +| Retries | `retryCount` | Average number of retries per message | +| Message Size | `messageSize` | Maximum message size over the specified period | The `queueMessageOperationsAdaptiveGroups` dataset provides the following dimensions for filtering and grouping queries: -* `queueID` - ID of the queue -* `actionType` - The type of message operation. Can be `WriteMessage`, `ReadMessage` or `DeleteMessage` -* `consumerType` - The queue consumer type. Can be `worker` or `http`. Only applicable for `ReadMessage` and `DeleteMessage` action types -* `outcome` - The outcome of the mesage operation. Only applicable for `DeleteMessage` action types. Can be `success`, `dlq` or `fail`. -* `datetime` - Timestamp for the message operation -* `date` - Timestamp for the message operation, truncated to the start of a day -* `datetimeHour` - Timestamp for the message operation, truncated to the start of an hour -* `datetimeMinute` - Timestamp for the message operation, truncated to the start of a minute + +- `queueID` - ID of the queue +- `actionType` - The type of message operation. Can be `WriteMessage`, `ReadMessage` or `DeleteMessage` +- `consumerType` - The queue consumer type. Can be `worker` or `http`. Only applicable for `ReadMessage` and `DeleteMessage` action types +- `outcome` - The outcome of the mesage operation. Only applicable for `DeleteMessage` action types. Can be `success`, `dlq` or `fail`. +- `datetime` - Timestamp for the message operation +- `date` - Timestamp for the message operation, truncated to the start of a day +- `datetimeHour` - Timestamp for the message operation, truncated to the start of an hour +- `datetimeMinute` - Timestamp for the message operation, truncated to the start of a minute ## Example GraphQL Queries ### Get average queue backlog over time period -```graphql -query QueueBacklog($accountTag: string!, $queueId: string!, $datetimeStart: Time!, $datetimeEnd: Time!) { - viewer { - accounts(filter: {accountTag: $accountTag}) { - queueBacklogAdaptiveGroups( - limit: 10000 - filter: { - queueId: $queueId - datetime_geq: $datetimeStart - datetime_leq: $datetimeEnd - } - ) { - avg { - messages - bytes - } - } - } - } +```graphql graphql-api-explorer +query QueueBacklog( + $accountTag: string! + $queueId: string! + $datetimeStart: Time! + $datetimeEnd: Time! +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + queueBacklogAdaptiveGroups( + limit: 10000 + filter: { + queueId: $queueId + datetime_geq: $datetimeStart + datetime_leq: $datetimeEnd + } + ) { + avg { + messages + bytes + } + } + } + } } ``` ### Get average consumer concurrency by hour -```graphql -query QueueConcurrencyByHour($accountTag: string!, $queueId: string!, $datetimeStart: Time!, $datetimeEnd: Time!) { - viewer { - accounts(filter: {accountTag: $accountTag}) { - queueConsumerMetricsAdaptiveGroups( - limit: 10000 - filter: { - queueId: $queueId - datetime_geq: $datetimeStart - datetime_leq: $datetimeEnd - } - orderBy: [datetimeHour_DESC] - ) { - avg { - concurrency - } - dimensions { - datetimeHour - } - } - } - } +```graphql graphql-api-explorer +query QueueConcurrencyByHour( + $accountTag: string! + $queueId: string! + $datetimeStart: Time! + $datetimeEnd: Time! +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + queueConsumerMetricsAdaptiveGroups( + limit: 10000 + filter: { + queueId: $queueId + datetime_geq: $datetimeStart + datetime_leq: $datetimeEnd + } + orderBy: [datetimeHour_DESC] + ) { + avg { + concurrency + } + dimensions { + datetimeHour + } + } + } + } } ``` ### Get message operations by minute -```graphql -query QueueMessageOperationsByMinute($accountTag: string!, $queueId: string!, $datetimeStart: Date!, $datetimeEnd: Date!) { - viewer { - accounts(filter: {accountTag: $accountTag}) { - queueMessageOperationsAdaptiveGroups( - limit: 10000 - filter: { - queueId: $queueId - datetime_geq: $datetimeStart - datetime_leq: $datetimeEnd - } - orderBy: [datetimeMinute_DESC] - ) { - count - sum { - bytes - } - dimensions { - datetimeMinute - } - } - } - } +```graphql graphql-api-explorer +query QueueMessageOperationsByMinute( + $accountTag: string! + $queueId: string! + $datetimeStart: Date! + $datetimeEnd: Date! +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + queueMessageOperationsAdaptiveGroups( + limit: 10000 + filter: { + queueId: $queueId + datetime_geq: $datetimeStart + datetime_leq: $datetimeEnd + } + orderBy: [datetimeMinute_DESC] + ) { + count + sum { + bytes + } + dimensions { + datetimeMinute + } + } + } + } } ``` diff --git a/src/content/docs/r2/platform/metrics-analytics.mdx b/src/content/docs/r2/platform/metrics-analytics.mdx index 65587739494807c..f8ae2641bee9d19 100644 --- a/src/content/docs/r2/platform/metrics-analytics.mdx +++ b/src/content/docs/r2/platform/metrics-analytics.mdx @@ -1,7 +1,6 @@ --- pcx_content_type: concept title: Metrics and analytics - --- R2 exposes analytics that allow you to inspect the requests and storage of the buckets in your account. @@ -12,21 +11,21 @@ The metrics displayed for a bucket in the [Cloudflare dashboard](https://dash.cl R2 currently has two datasets: -|
Dataset
|
GraphQL Dataset Name
| Description | -| ---------------------------------------- | ---------------------------------------------------- | -------------------------------------------------------------------- | -| Operations | `r2OperationsAdaptiveGroups` | This dataset consists of the operations taken buckets of an account. | -| Storage | `r2StorageAdaptiveGroups` | This dataset consists of the storage of buckets an account. | +|
Dataset
|
GraphQL Dataset Name
| Description | +| --------------------------------------- | ---------------------------------------------------- | -------------------------------------------------------------------- | +| Operations | `r2OperationsAdaptiveGroups` | This dataset consists of the operations taken buckets of an account. | +| Storage | `r2StorageAdaptiveGroups` | This dataset consists of the storage of buckets an account. | ### Operations Dataset -|
Field
| Description | -| --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| actionType | The name of the operation performed. | -| actionStatus | The status of the operation. Can be `success`, `userError`, or `internalError`. | -| bucketName | The bucket this operation was performed on if applicable. For buckets with a jurisdiction specified, you must include the jurisdiction followed by an underscore before the bucket name. For example: eu\_your-bucket-name | -| objectName | The object this operation was performed on if applicable. | -| responseStatusCode | The http status code returned by this operation. | -| datetime | The time of the request. | +|
Field
| Description | +| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| actionType | The name of the operation performed. | +| actionStatus | The status of the operation. Can be `success`, `userError`, or `internalError`. | +| bucketName | The bucket this operation was performed on if applicable. For buckets with a jurisdiction specified, you must include the jurisdiction followed by an underscore before the bucket name. For example: eu_your-bucket-name | +| objectName | The object this operation was performed on if applicable. | +| responseStatusCode | The http status code returned by this operation. | +| datetime | The time of the request. | ### Storage Dataset @@ -61,10 +60,15 @@ You can programmatically query analytics for your R2 buckets via the [GraphQL An To query the volume of each operation type on a bucket for a given time period you can run a query as such -```graphql -query { +```graphql graphql-api-explorer +query R2VolumeExample( + $accountTag: string! + $startDate: Time + $endDate: Time + $bucketName: string +) { viewer { - accounts(filter: { accountTag: $accountId }) { + accounts(filter: { accountTag: $accountTag }) { r2OperationsAdaptiveGroups( limit: 10000 filter: { @@ -91,10 +95,15 @@ The `bucketName` field can be removed to get an account level overview of operat To query the storage of a bucket over a given time period you can run a query as such. -```graphql -query { +```graphql graphql-api-explorer +query R2StorageExample( + $accountTag: string! + $startDate: Time + $endDate: Time + $bucketName: string +) { viewer { - accounts(filter: { accountTag: $accountId }) { + accounts(filter: { accountTag: $accountTag }) { r2StorageAdaptiveGroups( limit: 10000 filter: { @@ -105,9 +114,9 @@ query { orderBy: [datetime_DESC] ) { max { - objectCount, - uploadCount, - payloadSize, + objectCount + uploadCount + payloadSize metadataSize } dimensions { diff --git a/src/content/docs/stream/getting-analytics/fetching-bulk-analytics.mdx b/src/content/docs/stream/getting-analytics/fetching-bulk-analytics.mdx index d95d31fdfa467a3..0af8a9465d1ae68 100644 --- a/src/content/docs/stream/getting-analytics/fetching-bulk-analytics.mdx +++ b/src/content/docs/stream/getting-analytics/fetching-bulk-analytics.mdx @@ -3,7 +3,6 @@ pcx_content_type: reference title: GraphQL Analytics API sidebar: order: 1 - --- Stream provides analytics about both live video and video uploaded to Stream, via the GraphQL API described below, as well as in the [Stream dashboard](https://dash.cloudflare.com/?to=/:account/stream/analytics). @@ -43,73 +42,68 @@ Some filters, like `date`, can be used with operators, such as `gt` (greater tha #### Get minutes viewed by country -```graphql title="GraphQL request" -query { - viewer { - accounts(filter:{ - accountTag:"" - }) { - streamMinutesViewedAdaptiveGroups( - filter: { - date_geq: "2022-02-01" - date_lt: "2022-03-01" - } - orderBy:[sum_minutesViewed_DESC] - limit: 100 - ) { - sum { - minutesViewed - } - dimensions{ - uid - clientCountryName - } - } - } - } +```graphql graphql-api-explorer title="GraphQL request" +query StreamGetMinutesExample($accountTag: string!, $start: Date, $end: Date) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + streamMinutesViewedAdaptiveGroups( + filter: { date_geq: $start, date_lt: $end } + orderBy: [sum_minutesViewed_DESC] + limit: 100 + ) { + sum { + minutesViewed + } + dimensions { + uid + clientCountryName + } + } + } + } } ``` ```json title="GraphQL response" { - "data": { - "viewer": { - "accounts": [ - { - "streamMinutesViewedAdaptiveGroups": [ - { - "dimensions": { - "clientCountryName": "US", - "uid": "73c514082b154945a753d0011e9d7525" - }, - "sum": { - "minutesViewed": 2234 - } - }, - { - "dimensions": { - "clientCountryName": "CN", - "uid": "73c514082b154945a753d0011e9d7525" - }, - "sum": { - "minutesViewed": 700 - } - }, - { - "dimensions": { - "clientCountryName": "IN", - "uid": "73c514082b154945a753d0011e9d7525" - }, - "sum": { - "minutesViewed": 553 - } - } - ] - } - ] - } - }, - "errors": null + "data": { + "viewer": { + "accounts": [ + { + "streamMinutesViewedAdaptiveGroups": [ + { + "dimensions": { + "clientCountryName": "US", + "uid": "73c514082b154945a753d0011e9d7525" + }, + "sum": { + "minutesViewed": 2234 + } + }, + { + "dimensions": { + "clientCountryName": "CN", + "uid": "73c514082b154945a753d0011e9d7525" + }, + "sum": { + "minutesViewed": 700 + } + }, + { + "dimensions": { + "clientCountryName": "IN", + "uid": "73c514082b154945a753d0011e9d7525" + }, + "sum": { + "minutesViewed": 553 + } + } + ] + } + ] + } + }, + "errors": null } ``` @@ -119,44 +113,42 @@ GraphQL API supports seek pagination: using filters, you can specify the last vi The query below will return data for 2 videos that follow video UID `5646153f8dea17f44d542a42e76cfd`: -```graphql title="GraphQL query" -query { - viewer { - accounts(filter:{ - accountTag:"6c04ee5623f70a112c8f488e4c7a2409" - - }) { - videoPlaybackEventsAdaptiveGroups( - filter: { - date_geq: "2020-09-01" - date_lt: "2020-09-25" - uid_gt:"5646153f8dea17f44d542a42e76cfd" - } - orderBy:[uid_ASC] - limit: 2 - ) { - count - sum { - timeViewedMinutes - } - dimensions{ - uid - } - } - } - } +```graphql graphql-api-explorer='{"uId": "5646153f8dea17f44d542a42e76cfd"}' title="GraphQL query" +query StreamPaginationExample( + $accountTag: string! + $start: Date + $end: Date + $uId: string +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + videoPlaybackEventsAdaptiveGroups( + filter: { date_geq: $start, date_lt: $end, uid_gt: $uId } + orderBy: [uid_ASC] + limit: 2 + ) { + count + sum { + timeViewedMinutes + } + dimensions { + uid + } + } + } + } } ``` Here are the steps to implementing pagination: -1. Call the first query without uid\_gt filter to get the first set of videos +1. Call the first query without uid_gt filter to get the first set of videos 2. Grab the last video UID from the response from the first query -3. Call next query by specifying uid\_gt property and set it to the last video UID. This will return the next set of videos +3. Call next query by specifying uid_gt property and set it to the last video UID. This will return the next set of videos For more on pagination, refer to the [Cloudflare GraphQL Analytics API docs](/analytics/graphql-api/features/pagination/). ## Limitations -* The maximum query interval in a single query is 31 days -* The maximum data retention period is 90 days +- The maximum query interval in a single query is 31 days +- The maximum data retention period is 90 days diff --git a/src/content/docs/workflows/observability/metrics-analytics.mdx b/src/content/docs/workflows/observability/metrics-analytics.mdx index e67e25e73e4495d..e7b159e490285a2 100644 --- a/src/content/docs/workflows/observability/metrics-analytics.mdx +++ b/src/content/docs/workflows/observability/metrics-analytics.mdx @@ -3,7 +3,6 @@ pcx_content_type: concept title: Metrics and analytics sidebar: order: 10 - --- Workflows expose metrics that allow you to inspect and measure Workflow execution, error rates, steps, and total duration across each (and all) of your Workflows. @@ -14,9 +13,9 @@ The metrics displayed in the [Cloudflare dashboard](https://dash.cloudflare.com/ Workflows currently export the below metrics within the `workflowsAdaptiveGroups` GraphQL dataset. -| Metric | GraphQL Field Name | Description | -| ---------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -| Read Queries (qps) | `readQueries` | The number of read queries issued against a database. This is the raw number of read queries, and is not used for billing. | +| Metric | GraphQL Field Name | Description | +| ------------------ | ------------------ | -------------------------------------------------------------------------------------------------------------------------- | +| Read Queries (qps) | `readQueries` | The number of read queries issued against a database. This is the raw number of read queries, and is not used for billing. | Metrics can be queried (and are retained) for the past 31 days. @@ -24,16 +23,16 @@ Metrics can be queried (and are retained) for the past 31 days. The `workflowsAdaptiveGroups` dataset provides the following dimensions for filtering and grouping query results: -* `workflowName` - Workflow name - e.g. `my-workflow` -* `instanceId` - Instance ID -* `stepName` - Step name -* `eventType` - Event type (see [event types](#event-types)) -* `stepCount` - Step number within a given instance -* `date` - The date when the Workflow was triggered -* `datetimeFifteenMinutes` - The date and time truncated to fifteen minutes -* `datetimeFiveMinutes` - The date and time truncated to five minutes -* `datetimeHour` - The date and time truncated to the hour -* `datetimeMinute` - The date and time truncated to the minute +- `workflowName` - Workflow name - e.g. `my-workflow` +- `instanceId` - Instance ID +- `stepName` - Step name +- `eventType` - Event type (see [event types](#event-types)) +- `stepCount` - Step number within a given instance +- `date` - The date when the Workflow was triggered +- `datetimeFifteenMinutes` - The date and time truncated to fifteen minutes +- `datetimeFiveMinutes` - The date and time truncated to five minutes +- `datetimeHour` - The date and time truncated to the hour +- `datetimeMinute` - The date and time truncated to the minute ### Event types @@ -43,22 +42,22 @@ The possible values for `eventType` are documented below: #### Workflows-level status labels -* `WORKFLOW_QUEUED` - the Workflow is queued, but not currently running. This can happen when you are at the [concurrency limit](/workflows/reference/limits/) and new instances are waiting for currently running instances to complete. -* `WORKFLOW_START` - the Workflow has started and is running. -* `WORKFLOW_SUCCESS` - the Workflow finished without errors. -* `WORKFLOW_FAILURE` - the Workflow failed due to errors (exhausting retries, errors thrown, etc). -* `WORKFLOW_TERMINATED` - the Workflow was explicitly terminated. +- `WORKFLOW_QUEUED` - the Workflow is queued, but not currently running. This can happen when you are at the [concurrency limit](/workflows/reference/limits/) and new instances are waiting for currently running instances to complete. +- `WORKFLOW_START` - the Workflow has started and is running. +- `WORKFLOW_SUCCESS` - the Workflow finished without errors. +- `WORKFLOW_FAILURE` - the Workflow failed due to errors (exhausting retries, errors thrown, etc). +- `WORKFLOW_TERMINATED` - the Workflow was explicitly terminated. #### Step-level status labels -* `STEP_START` - the step has started and is running. -* `STEP_SUCCESS` - the step finished without errors. -* `STEP_FAILURE` - the step failed due to an error. -* `SLEEP_START` - the step is sleeping. -* `SLEEP_COMPLETE` - the step last finished sleeping. -* `ATTEMPT_START` - a step is retrying. -* `ATTEMPT_SUCCESS` - the retry succeeded. -* `ATTEMPT_FAILURE` - the retry attempt failed. +- `STEP_START` - the step has started and is running. +- `STEP_SUCCESS` - the step finished without errors. +- `STEP_FAILURE` - the step failed due to an error. +- `SLEEP_START` - the step is sleeping. +- `SLEEP_COMPLETE` - the step last finished sleeping. +- `ATTEMPT_START` - a step is retrying. +- `ATTEMPT_SUCCESS` - the retry succeeded. +- `ATTEMPT_FAILURE` - the retry attempt failed. ## View metrics in the dashboard @@ -80,115 +79,129 @@ Workflows GraphQL datasets require an `accountTag` filter with your Cloudflare a To query the count (number of workflow invocations) and sum of `wallTime` for a given `$workflowName` between `$datetimeStart` and `$datetimeEnd`, grouping by `date`: -```graphql -{ - viewer { - accounts(filter: { accountTag: $accountTag }) { - wallTime: workflowsAdaptiveGroups( - limit: 10000 - filter: { - datetimeHour_geq: $datetimeStart, - datetimeHour_leq: $datetimeEnd, - workflowName: $workflowName - } - orderBy: [count_DESC] - ) { - count - sum { - wallTime - } - dimensions { - date: datetimeHour - } - } - } - } +```graphql graphql-api-explorer +query WorkflowInvocationsExample( + $accountTag: string! + $datetimeStart: Time + $datetimeEnd: Time + $workflowName: string +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + wallTime: workflowsAdaptiveGroups( + limit: 10000 + filter: { + datetimeHour_geq: $datetimeStart + datetimeHour_leq: $datetimeEnd + workflowName: $workflowName + } + orderBy: [count_DESC] + ) { + count + sum { + wallTime + } + dimensions { + date: datetimeHour + } + } + } + } } ``` Here we are doing the same for `wallTime`, `instanceRuns` and `stepCount` in the same query: -```graphql -{ - viewer { - accounts(filter: { accountTag: $accountTag }) { - instanceRuns: workflowsAdaptiveGroups( - limit: 10000 - filter: { - datetimeHour_geq: $datetimeStart - datetimeHour_leq: $datetimeEnd - workflowName: $workflowName - eventType: "WORKFLOW_START" - } - orderBy: [count_DESC] - ) { - count - dimensions { - date: datetimeHour - } - } - stepCount: workflowsAdaptiveGroups( - limit: 10000 - filter: { - datetimeHour_geq: $datetimeStart - datetimeHour_leq: $datetimeEnd - workflowName: $workflowName - eventType: "STEP_START" - } - orderBy: [count_DESC] - ) { - count - dimensions { - date: datetimeHour - } - } - wallTime: workflowsAdaptiveGroups( - limit: 10000 - filter: { - datetimeHour_geq: $datetimeStart - datetimeHour_leq: $datetimeEnd - workflowName: $workflowName - } - orderBy: [count_DESC] - ) { - count - sum { - wallTime - } - dimensions { - date: datetimeHour - } - } - } - } +```graphql graphql-api-explorer +query WorkflowInvocationsExample2( + $accountTag: string! + $datetimeStart: Time + $datetimeEnd: Time + $workflowName: string +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + instanceRuns: workflowsAdaptiveGroups( + limit: 10000 + filter: { + datetimeHour_geq: $datetimeStart + datetimeHour_leq: $datetimeEnd + workflowName: $workflowName + eventType: "WORKFLOW_START" + } + orderBy: [count_DESC] + ) { + count + dimensions { + date: datetimeHour + } + } + stepCount: workflowsAdaptiveGroups( + limit: 10000 + filter: { + datetimeHour_geq: $datetimeStart + datetimeHour_leq: $datetimeEnd + workflowName: $workflowName + eventType: "WORKFLOW_START" + } + orderBy: [count_DESC] + ) { + count + dimensions { + date: datetimeHour + } + } + wallTime: workflowsAdaptiveGroups( + limit: 10000 + filter: { + datetimeHour_geq: $datetimeStart + datetimeHour_leq: $datetimeEnd + workflowName: $workflowName + } + orderBy: [count_DESC] + ) { + count + sum { + wallTime + } + dimensions { + date: datetimeHour + } + } + } + } } ``` Here lets query `workflowsAdaptive` for raw data about `$instanceId` between `$datetimeStart` and `$datetimeEnd`: -```graphql -{ - viewer { - accounts(filter: { accountTag: $accountTag }) { - workflowsAdaptive( - limit: 100 - filter: { - datetime_geq: $datetimeStart - datetime_leq: $datetimeEnd - instanceId: $instanceId - } - orderBy: [datetime_ASC] - ) { - datetime - eventType - workflowName - instanceId - stepName - stepCount - wallTime - } - } - } +```graphql graphql-api-explorer +query WorkflowsAdaptiveExample( + $accountTag: string! + $datetimeStart: Time + $datetimeEnd: Time + $instanceId: string +) { + viewer { + accounts(filter: { accountTag: $accountTag }) { + workflowsAdaptive( + limit: 100 + filter: { + datetime_geq: $datetimeStart + datetime_leq: $datetimeEnd + instanceId: $instanceId + } + orderBy: [datetime_ASC] + ) { + datetime + eventType + workflowName + instanceId + stepCount + wallTime + } + } + } } ``` diff --git a/src/content/docs/zaraz/monitoring/monitoring-api.mdx b/src/content/docs/zaraz/monitoring/monitoring-api.mdx index 1e7032316f19a71..21c931275506aae 100644 --- a/src/content/docs/zaraz/monitoring/monitoring-api.mdx +++ b/src/content/docs/zaraz/monitoring/monitoring-api.mdx @@ -28,28 +28,28 @@ You can construct any query you'd like using the above datasets, but here are so Query for the count of Zaraz events, grouped by time. -```graphql +```graphql graphql-api-explorer='{"orderBy": "datetimeHour_ASC"}' query ZarazEvents( - $zoneTag: string - $limit: uint64! - $start: Date - $end: Date - $orderBy: [ZoneZarazTrackAdaptiveGroupsOrderBy!] + $zoneTag: string + $limit: uint64! + $start: Time + $end: Time + $orderBy: ZoneZarazTrackAdaptiveGroupsOrderBy! ) { - viewer { - zones(filter: { zoneTag: $zoneTag }) { - data: zarazTrackAdaptiveGroups( - limit: $limit - filter: { datetimeHour_geq: $start, datetimeHour_leq: $end } - orderBy: [$orderBy] - ) { - count - dimensions { - ts: datetimeHour - } - } - } - } + viewer { + zones(filter: { zoneTag: $zoneTag }) { + data: zarazTrackAdaptiveGroups( + limit: $limit + filter: { datetimeHour_geq: $start, datetimeHour_leq: $end } + orderBy: [$orderBy] + ) { + count + dimensions { + ts: datetimeHour + } + } + } + } } ``` @@ -57,28 +57,28 @@ query ZarazEvents( Query for the count of Zaraz loads, grouped by time. -```graphql +```graphql graphql-api-explorer='{"orderBy": "date_ASC"}' query ZarazLoads( - $zoneTag: string - $limit: uint64! - $start: Date - $end: Date - $orderBy: [ZoneZarazTriggersAdaptiveGroupsOrderBy!] + $zoneTag: string + $limit: uint64! + $start: Date + $end: Date + $orderBy: ZoneZarazTriggersAdaptiveGroupsOrderBy! ) { - viewer { - zones(filter: { zoneTag: $zoneTag }) { - data: zarazTriggersAdaptiveGroups( - limit: $limit - filter: { date_geq: $start, date_leq: $end, triggerName: Pageview } - orderBy: [$orderBy] - ) { - count - dimensions { - ts: date - } - } - } - } + viewer { + zones(filter: { zoneTag: $zoneTag }) { + data: zarazTriggersAdaptiveGroups( + limit: $limit + filter: { date_geq: $start, date_leq: $end, triggerName: Pageview } + orderBy: [$orderBy] + ) { + count + dimensions { + ts: date + } + } + } + } } ``` @@ -86,28 +86,27 @@ query ZarazLoads( Query for the total execution count of each trigger processed by Zaraz. -```graphql +```graphql graphql-api-explorer query ZarazTriggers( - $zoneTag: string - $limit: uint64! - $start: Date - $end: Date - $orderBy: [uint64!] + $zoneTag: string + $limit: uint64! + $start: Date + $end: Date ) { - viewer { - zones(filter: { zoneTag: $zoneTag }) { - data: zarazTriggersAdaptiveGroups( - limit: $limit - filter: { date_geq: $start, date_leq: $end } - orderBy: [count_DESC] - ) { - count - dimensions { - name: triggerName - } - } - } - } + viewer { + zones(filter: { zoneTag: $zoneTag }) { + data: zarazTriggersAdaptiveGroups( + limit: $limit + filter: { date_geq: $start, date_leq: $end } + orderBy: [count_DESC] + ) { + count + dimensions { + name: triggerName + } + } + } + } } ``` @@ -115,34 +114,34 @@ query ZarazTriggers( Query for the count of 400 server-side responses, grouped by time and URL. -```graphql +```graphql graphql-api-explorer='{"orderBy": "datetimeHour_ASC"}' query ErroneousResponses( - $zoneTag: string - $limit: uint64! - $start: Date - $end: Date - $orderBy: [ZoneZarazFetchAdaptiveGroupsOrderBy!] + $zoneTag: string + $limit: uint64! + $start: Time + $end: Time + $orderBy: ZoneZarazFetchAdaptiveGroupsOrderBy! ) { - viewer { - zones(filter: { zoneTag: $zoneTag }) { - data: zarazFetchAdaptiveGroups( - limit: $limit - filter: { - datetimeHour_geq: $start - datetimeHour_leq: $end - url_neq: "" - status: 400 - } - orderBy: [$orderBy] - ) { - count - dimensions { - ts: datetimeHour - name: url - } - } - } - } + viewer { + zones(filter: { zoneTag: $zoneTag }) { + data: zarazFetchAdaptiveGroups( + limit: $limit + filter: { + datetimeHour_geq: $start + datetimeHour_leq: $end + url_neq: "" + status: 400 + } + orderBy: [$orderBy] + ) { + count + dimensions { + ts: datetimeHour + name: url + } + } + } + } } ``` @@ -152,11 +151,11 @@ query ErroneousResponses( ```json { - "zoneTag": "d6dfdf32c704a77ac227243a5eb5ca61", - "start": "2025-01-01T00:00:00Z", - "end": "2025-01-30T00:00:00Z", - "limit": 10000, - "orderBy": "datetimeHour_ASC" + "zoneTag": "d6dfdf32c704a77ac227243a5eb5ca61", + "start": "2025-01-01T00:00:00Z", + "end": "2025-01-30T00:00:00Z", + "limit": 10000, + "orderBy": "datetimeHour_ASC" } ``` diff --git a/src/plugins/expressive-code/graphql-api-explorer.js b/src/plugins/expressive-code/graphql-api-explorer.js new file mode 100644 index 000000000000000..c01958f10d1737c --- /dev/null +++ b/src/plugins/expressive-code/graphql-api-explorer.js @@ -0,0 +1,157 @@ +// @ts-check +import { definePlugin } from "@expressive-code/core"; + +import lzstring from "lz-string"; + +/** + * @param {string} gql + */ +async function compressGql(gql) { + return lzstring.compressToEncodedURIComponent(gql); +} + +/** + * See CONTRIBUTING.md for instructions on how to use this plugin. + * @param {string} query + */ +function autoPopulateGraphQLVariables(query) { + const varPattern = /\$(\w+):\s*([\w![\]]+)/g; + const now = new Date(); + /** @type {Record} */ + const variables = {}; + let match; + + while ((match = varPattern.exec(query)) !== null) { + const [, varName, varTypeRaw] = match; + + const varType = varTypeRaw.replace(/[![\]]/g, ""); + + // Type- and name-based inference + if (varType === "Time") { + const value = /start/i.test(varName) + ? new Date(now.getTime() - 6 * 60 * 60 * 1000) + : now; + variables[varName] = value.toISOString().split(".")[0] + "Z"; + } else if (varType === "Date") { + const value = /start/i.test(varName) + ? new Date(now.getTime() - 24 * 60 * 60 * 1000) + : now; + variables[varName] = value.toISOString().split("T")[0]; // e.g., "2025-05-05" + } else if (varType.toLowerCase() === "string") { + if (/zoneTag/i.test(varName)) { + variables[varName] = "ZONE_ID"; + } else if (/accountTag/i.test(varName)) { + variables[varName] = "ACCOUNT_ID"; + } else if (/id/i.test(varName)) { + variables[varName] = "REPLACE_WITH_ID"; + } else { + variables[varName] = "REPLACE_WITH_STRING"; + } + } else if (varType.indexOf("int") > -1) { + if (/limit/i.test(varName)) { + variables[varName] = 100; + } + } + } + + return variables; +} + +export default () => { + return definePlugin({ + name: "Adds 'Run in GraphQL API Explorer' button to GraphQL codeblocks", + baseStyles: ` + .wrapper { + box-shadow: var(--ec-frm-frameBoxShdCssVal); + border-radius: calc(var(--ec-brdRad) + var(--ec-brdWd)); + margin-top: 0 !important; + } + + .expressive-code:has(.gql-explorer-frame) .frame { + box-shadow: unset; + + & > pre { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + } + } + + .gql-explorer-frame { + border: var(--ec-brdWd) solid var(--ec-brdCol); + border-top: unset; + border-bottom-left-radius: calc(var(--ec-brdRad) + var(--ec-brdWd)); + border-bottom-right-radius: calc(var(--ec-brdRad) + var(--ec-brdWd)); + }`, + hooks: { + postprocessRenderedBlock: async (context) => { + if ( + !context.codeBlock.meta.includes("graphql-api-explorer") && + !context.codeBlock.meta.includes("graphql") + ) + return; + + let transformedVariables = autoPopulateGraphQLVariables( + context.codeBlock.code, + ); + transformedVariables = { + ...transformedVariables, + ...JSON.parse( + context.codeBlock.metaOptions.getString("graphql-api-explorer") ?? + "{}", + ), + }; + + const query = await compressGql(context.codeBlock.code); + const variables = await compressGql( + JSON.stringify(transformedVariables), + ); + + context.renderData.blockAst = { + type: "element", + tagName: "div", + properties: { + className: ["wrapper"], + }, + children: [ + context.renderData.blockAst, + { + type: "element", + tagName: "div", + properties: { + className: [ + "gql-explorer-frame", + "flex!", + "p-4!", + "justify-end!", + "items-center!", + ], + }, + children: [ + { + type: "element", + tagName: "a", + properties: { + className: [ + "bg-cl1-brand-orange!", + "rounded-sm!", + "px-6!", + "py-2!", + "text-cl1-black!", + "font-medium!", + "no-underline!", + ], + href: `https://graphql.cloudflare.com/explorer?query=${query}&variables=${variables}`, + target: "_blank", + }, + children: [ + { type: "text", value: "Run in GraphQL API Explorer" }, + ], + }, + ], + }, + ], + }; + }, + }, + }); +};