From fb7d6dc598542f90feaf7f562a6d81efed007c1f Mon Sep 17 00:00:00 2001 From: Dave Clarke Date: Mon, 17 Aug 2026 18:15:50 +0100 Subject: [PATCH 01/27] v1 --- .github/CODEOWNERS | 1 + plugins/Cloudflare/v1/configValidation.json | 31 + .../relate-pages-project-to-zone.json | 20 + .../relate-queue-to-worker.json | 20 + .../relate-resources-to-account.json | 34 + .../relate-worker-binding-to-d1-database.json | 20 + ...r-binding-to-durable-object-namespace.json | 20 + ...e-worker-binding-to-hyperdrive-config.json | 20 + ...relate-worker-binding-to-kv-namespace.json | 20 + .../relate-worker-binding-to-queue.json | 20 + .../relate-worker-binding-to-r2-bucket.json | 20 + ...ate-worker-binding-to-vectorize-index.json | 20 + .../relate-worker-binding-to-worker.json | 20 + .../relate-worker-to-zone.json | 37 + plugins/Cloudflare/v1/custom_types.json | 114 ++ .../Cloudflare/v1/dataStreams/accessApps.json | 85 ++ .../v1/dataStreams/accessLogins.json | 70 + .../Cloudflare/v1/dataStreams/accounts.json | 81 + .../v1/dataStreams/d1Analytics.json | 84 ++ .../v1/dataStreams/d1Databases.json | 75 + .../Cloudflare/v1/dataStreams/d1Storage.json | 49 + .../dataStreams/durableObjectInvocations.json | 110 ++ .../dataStreams/durableObjectNamespaces.json | 88 ++ .../v1/dataStreams/durableObjectStorage.json | 49 + .../v1/dataStreams/gatewayDnsQueries.json | 64 + .../v1/dataStreams/gatewayHttpRequests.json | 66 + .../v1/dataStreams/graphqlQuery.json | 69 + .../v1/dataStreams/hyperdriveConfigs.json | 48 + .../v1/dataStreams/hyperdriveQueries.json | 54 + .../v1/dataStreams/kvNamespaces.json | 77 + .../v1/dataStreams/kvOperations.json | 66 + .../Cloudflare/v1/dataStreams/kvStorage.json | 50 + .../dataStreams/loadBalancerPoolHealth.json | 79 + .../v1/dataStreams/loadBalancerPools.json | 85 ++ .../v1/dataStreams/pagesDeployments.json | 102 ++ .../v1/dataStreams/pagesProjects.json | 121 ++ .../v1/dataStreams/queueBacklog.json | 51 + .../dataStreams/queueMessageOperations.json | 95 ++ plugins/Cloudflare/v1/dataStreams/queues.json | 80 + .../Cloudflare/v1/dataStreams/r2Buckets.json | 70 + .../v1/dataStreams/r2Operations.json | 62 + .../Cloudflare/v1/dataStreams/r2Storage.json | 61 + .../v1/dataStreams/rumPageLoads.json | 71 + .../v1/dataStreams/rumWebVitals.json | 82 + .../v1/dataStreams/scripts/accessApps.js | 16 + .../v1/dataStreams/scripts/d1Databases.js | 14 + .../scripts/durableObjectNamespaces.js | 14 + .../dataStreams/scripts/gatewayDnsQueries.js | 32 + .../scripts/gatewayHttpRequests.js | 27 + .../v1/dataStreams/scripts/graphqlQuery.js | 88 ++ .../dataStreams/scripts/hyperdriveConfigs.js | 18 + .../v1/dataStreams/scripts/kvNamespaces.js | 11 + .../scripts/loadBalancerPoolHealth.js | 28 + .../dataStreams/scripts/loadBalancerPools.js | 21 + .../dataStreams/scripts/pagesDeployments.js | 19 + .../v1/dataStreams/scripts/pagesProjects.js | 23 + .../v1/dataStreams/scripts/queues.js | 27 + .../v1/dataStreams/scripts/r2Buckets.js | 14 + .../v1/dataStreams/scripts/rumPageLoads.js | 28 + .../dataStreams/scripts/tunnelConnections.js | 15 + .../v1/dataStreams/scripts/tunnels.js | 14 + .../dataStreams/scripts/vectorizeIndexes.js | 19 + .../v1/dataStreams/scripts/workerBindings.js | 44 + .../v1/dataStreams/scripts/workerRoutes.js | 18 + .../v1/dataStreams/scripts/workerScripts.js | 17 + .../dataStreams/scripts/workersAiInference.js | 33 + .../dataStreams/scripts/zoneCertificates.js | 15 + .../dataStreams/scripts/zoneDnsAnalytics.js | 28 + .../dataStreams/scripts/zoneFirewallEvents.js | 31 + .../scripts/zoneTrafficBreakdown.js | 28 + .../v1/dataStreams/tunnelConnections.json | 61 + .../Cloudflare/v1/dataStreams/tunnels.json | 136 ++ .../v1/dataStreams/vectorizeIndexes.json | 48 + .../v1/dataStreams/vectorizeQueries.json | 54 + .../v1/dataStreams/vectorizeStorage.json | 54 + .../v1/dataStreams/verifyToken.json | 39 + .../v1/dataStreams/workerBindings.json | 54 + .../v1/dataStreams/workerInvocations.json | 106 ++ .../v1/dataStreams/workerRoutes.json | 46 + .../v1/dataStreams/workerScripts.json | 85 ++ .../v1/dataStreams/workersAiInference.json | 78 + .../v1/dataStreams/zoneCertificates.json | 91 ++ .../v1/dataStreams/zoneDnsAnalytics.json | 69 + .../v1/dataStreams/zoneDnsRecords.json | 64 + .../v1/dataStreams/zoneFirewallEvents.json | 81 + .../v1/dataStreams/zoneHealthChecks.json | 87 ++ .../v1/dataStreams/zoneLoadBalancing.json | 59 + .../v1/dataStreams/zoneTraffic.json | 97 ++ .../v1/dataStreams/zoneTrafficBreakdown.json | 71 + plugins/Cloudflare/v1/dataStreams/zones.json | 180 +++ .../accessApplication.dash.json | 658 ++++++++ .../v1/defaultContent/account.dash.json | 791 ++++++++++ .../v1/defaultContent/d1Database.dash.json | 583 +++++++ .../v1/defaultContent/kvNamespace.dash.json | 566 +++++++ .../defaultContent/loadBalancerPool.dash.json | 379 +++++ .../v1/defaultContent/manifest.json | 52 + .../v1/defaultContent/overview.dash.json | 1189 +++++++++++++++ .../v1/defaultContent/pagesProject.dash.json | 309 ++++ .../v1/defaultContent/queue.dash.json | 549 +++++++ .../v1/defaultContent/r2Bucket.dash.json | 564 +++++++ .../Cloudflare/v1/defaultContent/scopes.json | 189 +++ .../v1/defaultContent/tunnel.dash.json | 306 ++++ .../v1/defaultContent/worker.dash.json | 495 ++++++ .../v1/defaultContent/zone.dash.json | 1343 +++++++++++++++++ plugins/Cloudflare/v1/docs/README.md | 140 ++ plugins/Cloudflare/v1/icon.svg | 6 + .../v1/indexDefinitions/default.json | 468 ++++++ plugins/Cloudflare/v1/metadata.json | 83 + plugins/Cloudflare/v1/ui.json | 10 + 109 files changed, 13443 insertions(+) create mode 100644 plugins/Cloudflare/v1/configValidation.json create mode 100644 plugins/Cloudflare/v1/correlationRules/relate-pages-project-to-zone.json create mode 100644 plugins/Cloudflare/v1/correlationRules/relate-queue-to-worker.json create mode 100644 plugins/Cloudflare/v1/correlationRules/relate-resources-to-account.json create mode 100644 plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-d1-database.json create mode 100644 plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-durable-object-namespace.json create mode 100644 plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-hyperdrive-config.json create mode 100644 plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-kv-namespace.json create mode 100644 plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-queue.json create mode 100644 plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-r2-bucket.json create mode 100644 plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-vectorize-index.json create mode 100644 plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-worker.json create mode 100644 plugins/Cloudflare/v1/correlationRules/relate-worker-to-zone.json create mode 100644 plugins/Cloudflare/v1/custom_types.json create mode 100644 plugins/Cloudflare/v1/dataStreams/accessApps.json create mode 100644 plugins/Cloudflare/v1/dataStreams/accessLogins.json create mode 100644 plugins/Cloudflare/v1/dataStreams/accounts.json create mode 100644 plugins/Cloudflare/v1/dataStreams/d1Analytics.json create mode 100644 plugins/Cloudflare/v1/dataStreams/d1Databases.json create mode 100644 plugins/Cloudflare/v1/dataStreams/d1Storage.json create mode 100644 plugins/Cloudflare/v1/dataStreams/durableObjectInvocations.json create mode 100644 plugins/Cloudflare/v1/dataStreams/durableObjectNamespaces.json create mode 100644 plugins/Cloudflare/v1/dataStreams/durableObjectStorage.json create mode 100644 plugins/Cloudflare/v1/dataStreams/gatewayDnsQueries.json create mode 100644 plugins/Cloudflare/v1/dataStreams/gatewayHttpRequests.json create mode 100644 plugins/Cloudflare/v1/dataStreams/graphqlQuery.json create mode 100644 plugins/Cloudflare/v1/dataStreams/hyperdriveConfigs.json create mode 100644 plugins/Cloudflare/v1/dataStreams/hyperdriveQueries.json create mode 100644 plugins/Cloudflare/v1/dataStreams/kvNamespaces.json create mode 100644 plugins/Cloudflare/v1/dataStreams/kvOperations.json create mode 100644 plugins/Cloudflare/v1/dataStreams/kvStorage.json create mode 100644 plugins/Cloudflare/v1/dataStreams/loadBalancerPoolHealth.json create mode 100644 plugins/Cloudflare/v1/dataStreams/loadBalancerPools.json create mode 100644 plugins/Cloudflare/v1/dataStreams/pagesDeployments.json create mode 100644 plugins/Cloudflare/v1/dataStreams/pagesProjects.json create mode 100644 plugins/Cloudflare/v1/dataStreams/queueBacklog.json create mode 100644 plugins/Cloudflare/v1/dataStreams/queueMessageOperations.json create mode 100644 plugins/Cloudflare/v1/dataStreams/queues.json create mode 100644 plugins/Cloudflare/v1/dataStreams/r2Buckets.json create mode 100644 plugins/Cloudflare/v1/dataStreams/r2Operations.json create mode 100644 plugins/Cloudflare/v1/dataStreams/r2Storage.json create mode 100644 plugins/Cloudflare/v1/dataStreams/rumPageLoads.json create mode 100644 plugins/Cloudflare/v1/dataStreams/rumWebVitals.json create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/accessApps.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/d1Databases.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/durableObjectNamespaces.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/gatewayDnsQueries.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/gatewayHttpRequests.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/graphqlQuery.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/hyperdriveConfigs.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/kvNamespaces.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/loadBalancerPoolHealth.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/loadBalancerPools.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/pagesDeployments.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/pagesProjects.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/queues.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/r2Buckets.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/rumPageLoads.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/tunnelConnections.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/tunnels.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/vectorizeIndexes.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/workerBindings.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/workerRoutes.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/workerScripts.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/workersAiInference.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/zoneCertificates.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/zoneDnsAnalytics.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/zoneFirewallEvents.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/zoneTrafficBreakdown.js create mode 100644 plugins/Cloudflare/v1/dataStreams/tunnelConnections.json create mode 100644 plugins/Cloudflare/v1/dataStreams/tunnels.json create mode 100644 plugins/Cloudflare/v1/dataStreams/vectorizeIndexes.json create mode 100644 plugins/Cloudflare/v1/dataStreams/vectorizeQueries.json create mode 100644 plugins/Cloudflare/v1/dataStreams/vectorizeStorage.json create mode 100644 plugins/Cloudflare/v1/dataStreams/verifyToken.json create mode 100644 plugins/Cloudflare/v1/dataStreams/workerBindings.json create mode 100644 plugins/Cloudflare/v1/dataStreams/workerInvocations.json create mode 100644 plugins/Cloudflare/v1/dataStreams/workerRoutes.json create mode 100644 plugins/Cloudflare/v1/dataStreams/workerScripts.json create mode 100644 plugins/Cloudflare/v1/dataStreams/workersAiInference.json create mode 100644 plugins/Cloudflare/v1/dataStreams/zoneCertificates.json create mode 100644 plugins/Cloudflare/v1/dataStreams/zoneDnsAnalytics.json create mode 100644 plugins/Cloudflare/v1/dataStreams/zoneDnsRecords.json create mode 100644 plugins/Cloudflare/v1/dataStreams/zoneFirewallEvents.json create mode 100644 plugins/Cloudflare/v1/dataStreams/zoneHealthChecks.json create mode 100644 plugins/Cloudflare/v1/dataStreams/zoneLoadBalancing.json create mode 100644 plugins/Cloudflare/v1/dataStreams/zoneTraffic.json create mode 100644 plugins/Cloudflare/v1/dataStreams/zoneTrafficBreakdown.json create mode 100644 plugins/Cloudflare/v1/dataStreams/zones.json create mode 100644 plugins/Cloudflare/v1/defaultContent/accessApplication.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/account.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/d1Database.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/kvNamespace.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/loadBalancerPool.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/manifest.json create mode 100644 plugins/Cloudflare/v1/defaultContent/overview.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/pagesProject.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/queue.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/r2Bucket.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/scopes.json create mode 100644 plugins/Cloudflare/v1/defaultContent/tunnel.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/worker.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/zone.dash.json create mode 100644 plugins/Cloudflare/v1/docs/README.md create mode 100644 plugins/Cloudflare/v1/icon.svg create mode 100644 plugins/Cloudflare/v1/indexDefinitions/default.json create mode 100644 plugins/Cloudflare/v1/metadata.json create mode 100644 plugins/Cloudflare/v1/ui.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c44719cf..1c79a6b0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,6 +8,7 @@ plugins/* @squaredup/community-moderators # Request review from original author plugins/AutoTask/* @TimWheeler-SQUP +plugins/Cloudflare/* @clarkd plugins/DattoRMM/* @TimWheeler-SQUP plugins/DigiCert/* @shaswot77 plugins/Huntress/* @Deenk diff --git a/plugins/Cloudflare/v1/configValidation.json b/plugins/Cloudflare/v1/configValidation.json new file mode 100644 index 00000000..c3f20c76 --- /dev/null +++ b/plugins/Cloudflare/v1/configValidation.json @@ -0,0 +1,31 @@ +{ + "steps": [ + { + "displayName": "Authenticate", + "dataStream": { "name": "verifyToken" }, + "required": true, + "error": "Could not authenticate with Cloudflare. Check the API token is valid, has not expired, and has not been revoked.", + "success": "Connected to Cloudflare successfully." + }, + { + "displayName": "Check account access", + "dataStream": { + "name": "accounts", + "config": { "errorOnEmptyResults": true } + }, + "required": false, + "error": "Authenticated, but no accounts are visible. Add the Account Settings Read permission and set Account Resources to Include all accounts.", + "success": "Accounts accessible." + }, + { + "displayName": "Check zone access", + "dataStream": { + "name": "zones", + "config": { "errorOnEmptyResults": true } + }, + "required": false, + "error": "Authenticated, but no zones are visible. Add the Zone Read permission and set Zone Resources to Include all zones.", + "success": "Zones accessible." + } + ] +} diff --git a/plugins/Cloudflare/v1/correlationRules/relate-pages-project-to-zone.json b/plugins/Cloudflare/v1/correlationRules/relate-pages-project-to-zone.json new file mode 100644 index 00000000..b4aacfa3 --- /dev/null +++ b/plugins/Cloudflare/v1/correlationRules/relate-pages-project-to-zone.json @@ -0,0 +1,20 @@ +{ + "displayName": "Pages Project served by Zone", + "source": { + "types": "Cloudflare Pages Project" + }, + "target": { + "types": "Cloudflare Zone" + }, + "conditions": [ + { + "sourceProperty": "domains", + "operator": "equals", + "targetProperty": "name" + } + ], + "labels": { + "forward": "served by", + "reverse": "serves" + } +} diff --git a/plugins/Cloudflare/v1/correlationRules/relate-queue-to-worker.json b/plugins/Cloudflare/v1/correlationRules/relate-queue-to-worker.json new file mode 100644 index 00000000..56ed2652 --- /dev/null +++ b/plugins/Cloudflare/v1/correlationRules/relate-queue-to-worker.json @@ -0,0 +1,20 @@ +{ + "displayName": "Queue consumed by Worker", + "source": { + "types": "Cloudflare Queue" + }, + "target": { + "types": "Cloudflare Worker" + }, + "conditions": [ + { + "sourceProperty": "consumerScripts", + "operator": "equals", + "targetProperty": "name" + } + ], + "labels": { + "forward": "consumed by", + "reverse": "consumes" + } +} diff --git a/plugins/Cloudflare/v1/correlationRules/relate-resources-to-account.json b/plugins/Cloudflare/v1/correlationRules/relate-resources-to-account.json new file mode 100644 index 00000000..b54d9878 --- /dev/null +++ b/plugins/Cloudflare/v1/correlationRules/relate-resources-to-account.json @@ -0,0 +1,34 @@ +{ + "displayName": "Account contains Resource", + "source": { + "types": [ + "Cloudflare Zone", + "Cloudflare Worker", + "Cloudflare R2 Bucket", + "Cloudflare Pages Project", + "Cloudflare D1 Database", + "Cloudflare KV Namespace", + "Cloudflare Queue", + "Cloudflare Tunnel", + "Cloudflare Load Balancer Pool", + "Cloudflare Access Application", + "Cloudflare Durable Object Namespace", + "Cloudflare Vectorize Index", + "Cloudflare Hyperdrive Config" + ] + }, + "target": { + "types": "Cloudflare Account" + }, + "conditions": [ + { + "sourceProperty": "accountId", + "operator": "equals", + "targetProperty": "rawId" + } + ], + "labels": { + "forward": "belongs to", + "reverse": "contains" + } +} diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-d1-database.json b/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-d1-database.json new file mode 100644 index 00000000..d09c627a --- /dev/null +++ b/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-d1-database.json @@ -0,0 +1,20 @@ +{ + "displayName": "Worker Binding targets D1 Database", + "source": { + "types": "Cloudflare Worker Binding" + }, + "target": { + "types": "Cloudflare D1 Database" + }, + "conditions": [ + { + "sourceProperty": "d1DatabaseId", + "operator": "equals", + "targetProperty": "rawId" + } + ], + "labels": { + "forward": "targets", + "reverse": "targeted by" + } +} diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-durable-object-namespace.json b/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-durable-object-namespace.json new file mode 100644 index 00000000..83819497 --- /dev/null +++ b/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-durable-object-namespace.json @@ -0,0 +1,20 @@ +{ + "displayName": "Worker Binding targets Durable Object Namespace", + "source": { + "types": "Cloudflare Worker Binding" + }, + "target": { + "types": "Cloudflare Durable Object Namespace" + }, + "conditions": [ + { + "sourceProperty": "durableObjectNamespaceId", + "operator": "equals", + "targetProperty": "rawId" + } + ], + "labels": { + "forward": "targets", + "reverse": "targeted by" + } +} diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-hyperdrive-config.json b/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-hyperdrive-config.json new file mode 100644 index 00000000..cf21944d --- /dev/null +++ b/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-hyperdrive-config.json @@ -0,0 +1,20 @@ +{ + "displayName": "Worker Binding targets Hyperdrive Config", + "source": { + "types": "Cloudflare Worker Binding" + }, + "target": { + "types": "Cloudflare Hyperdrive Config" + }, + "conditions": [ + { + "sourceProperty": "hyperdriveConfigId", + "operator": "equals", + "targetProperty": "rawId" + } + ], + "labels": { + "forward": "targets", + "reverse": "targeted by" + } +} diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-kv-namespace.json b/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-kv-namespace.json new file mode 100644 index 00000000..350e95a1 --- /dev/null +++ b/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-kv-namespace.json @@ -0,0 +1,20 @@ +{ + "displayName": "Worker Binding targets KV Namespace", + "source": { + "types": "Cloudflare Worker Binding" + }, + "target": { + "types": "Cloudflare KV Namespace" + }, + "conditions": [ + { + "sourceProperty": "kvNamespaceId", + "operator": "equals", + "targetProperty": "rawId" + } + ], + "labels": { + "forward": "targets", + "reverse": "targeted by" + } +} diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-queue.json b/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-queue.json new file mode 100644 index 00000000..ee11c30a --- /dev/null +++ b/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-queue.json @@ -0,0 +1,20 @@ +{ + "displayName": "Worker Binding targets Queue", + "source": { + "types": "Cloudflare Worker Binding" + }, + "target": { + "types": "Cloudflare Queue" + }, + "conditions": [ + { + "sourceProperty": "queueName", + "operator": "equals", + "targetProperty": "name" + } + ], + "labels": { + "forward": "targets", + "reverse": "targeted by" + } +} diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-r2-bucket.json b/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-r2-bucket.json new file mode 100644 index 00000000..78bd986a --- /dev/null +++ b/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-r2-bucket.json @@ -0,0 +1,20 @@ +{ + "displayName": "Worker Binding targets R2 Bucket", + "source": { + "types": "Cloudflare Worker Binding" + }, + "target": { + "types": "Cloudflare R2 Bucket" + }, + "conditions": [ + { + "sourceProperty": "r2BucketName", + "operator": "equals", + "targetProperty": "name" + } + ], + "labels": { + "forward": "targets", + "reverse": "targeted by" + } +} diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-vectorize-index.json b/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-vectorize-index.json new file mode 100644 index 00000000..51a7fdd9 --- /dev/null +++ b/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-vectorize-index.json @@ -0,0 +1,20 @@ +{ + "displayName": "Worker Binding targets Vectorize Index", + "source": { + "types": "Cloudflare Worker Binding" + }, + "target": { + "types": "Cloudflare Vectorize Index" + }, + "conditions": [ + { + "sourceProperty": "vectorizeIndexName", + "operator": "equals", + "targetProperty": "name" + } + ], + "labels": { + "forward": "targets", + "reverse": "targeted by" + } +} diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-worker.json b/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-worker.json new file mode 100644 index 00000000..36224232 --- /dev/null +++ b/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-worker.json @@ -0,0 +1,20 @@ +{ + "displayName": "Worker Binding declared by Worker", + "source": { + "types": "Cloudflare Worker Binding" + }, + "target": { + "types": "Cloudflare Worker" + }, + "conditions": [ + { + "sourceProperty": "scriptName", + "operator": "equals", + "targetProperty": "name" + } + ], + "labels": { + "forward": "declared by", + "reverse": "declares" + } +} diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-to-zone.json b/plugins/Cloudflare/v1/correlationRules/relate-worker-to-zone.json new file mode 100644 index 00000000..1ae58f92 --- /dev/null +++ b/plugins/Cloudflare/v1/correlationRules/relate-worker-to-zone.json @@ -0,0 +1,37 @@ +{ + "displayName": "Worker serves Zone", + "source": { + "types": "Cloudflare Worker" + }, + "bridge": { + "types": "Cloudflare Worker Route" + }, + "target": { + "types": "Cloudflare Zone" + }, + "sourceConditions": [ + { + "sourceProperty": "name", + "operator": "equals", + "targetProperty": "scriptName" + } + ], + "targetConditions": [ + { + "sourceProperty": "zoneId", + "operator": "equals", + "targetProperty": "rawId" + } + ], + "labels": { + "forward": "serves", + "reverse": "served by" + }, + "conditions": [ + { + "sourceProperty": "accountId", + "operator": "equals", + "targetProperty": "accountId" + } + ] +} diff --git a/plugins/Cloudflare/v1/custom_types.json b/plugins/Cloudflare/v1/custom_types.json new file mode 100644 index 00000000..862ca596 --- /dev/null +++ b/plugins/Cloudflare/v1/custom_types.json @@ -0,0 +1,114 @@ +[ + { + "name": "Cloudflare Account", + "sourceType": "Cloudflare Account", + "icon": "building", + "singular": "Account", + "plural": "Accounts" + }, + { + "name": "Cloudflare Zone", + "sourceType": "Cloudflare Zone", + "icon": "globe", + "singular": "Zone", + "plural": "Zones" + }, + { + "name": "Cloudflare Worker", + "sourceType": "Cloudflare Worker", + "icon": "bolt", + "singular": "Worker", + "plural": "Workers" + }, + { + "name": "Cloudflare R2 Bucket", + "sourceType": "Cloudflare R2 Bucket", + "icon": "bucket", + "singular": "R2 Bucket", + "plural": "R2 Buckets" + }, + { + "name": "Cloudflare Pages Project", + "sourceType": "Cloudflare Pages Project", + "icon": "file-code", + "singular": "Pages Project", + "plural": "Pages Projects" + }, + { + "name": "Cloudflare D1 Database", + "sourceType": "Cloudflare D1 Database", + "icon": "database", + "singular": "D1 Database", + "plural": "D1 Databases" + }, + { + "name": "Cloudflare KV Namespace", + "sourceType": "Cloudflare KV Namespace", + "icon": "key", + "singular": "KV Namespace", + "plural": "KV Namespaces" + }, + { + "name": "Cloudflare Queue", + "sourceType": "Cloudflare Queue", + "icon": "layer-group", + "singular": "Queue", + "plural": "Queues" + }, + { + "name": "Cloudflare Tunnel", + "sourceType": "Cloudflare Tunnel", + "icon": "road-lock", + "singular": "Tunnel", + "plural": "Tunnels" + }, + { + "name": "Cloudflare Load Balancer Pool", + "sourceType": "Cloudflare Load Balancer Pool", + "icon": "scale-balanced", + "singular": "Load Balancer Pool", + "plural": "Load Balancer Pools" + }, + { + "name": "Cloudflare Access Application", + "sourceType": "Cloudflare Access Application", + "icon": "shield-halved", + "singular": "Access Application", + "plural": "Access Applications" + }, + { + "name": "Cloudflare Durable Object Namespace", + "sourceType": "Cloudflare Durable Object Namespace", + "icon": "cubes", + "singular": "Durable Object Namespace", + "plural": "Durable Object Namespaces" + }, + { + "name": "Cloudflare Vectorize Index", + "sourceType": "Cloudflare Vectorize Index", + "icon": "vector-square", + "singular": "Vectorize Index", + "plural": "Vectorize Indexes" + }, + { + "name": "Cloudflare Hyperdrive Config", + "sourceType": "Cloudflare Hyperdrive Config", + "icon": "gauge-high", + "singular": "Hyperdrive Config", + "plural": "Hyperdrive Configs" + }, + { + "name": "Cloudflare Worker Route", + "sourceType": "Cloudflare Worker Route", + "icon": "route", + "singular": "Worker Route", + "plural": "Worker Routes" + }, + { + "name": "Cloudflare Worker Binding", + "sourceType": "Cloudflare Worker Binding", + "icon": "plug", + "singular": "Worker Binding", + "plural": "Worker Bindings" + } +] diff --git a/plugins/Cloudflare/v1/dataStreams/accessApps.json b/plugins/Cloudflare/v1/dataStreams/accessApps.json new file mode 100644 index 00000000..d56f7acc --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/accessApps.json @@ -0,0 +1,85 @@ +{ + "name": "accessApps", + "displayName": "Access Applications", + "description": "Zero Trust Access applications protected in a Cloudflare account", + "tags": [ + "Security" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/access/apps", + "postRequestScript": "accessApps.js", + "paging": { + "mode": "none" + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "appName", + "displayName": "Application", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare Access Application" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "domain", + "displayName": "Domain", + "shape": "string" + }, + { + "name": "appType", + "displayName": "Type", + "shape": "string" + }, + { + "name": "sessionDuration", + "displayName": "Session Duration", + "shape": "string" + }, + { + "name": "appLauncherVisible", + "displayName": "In App Launcher", + "shape": "boolean" + }, + { + "name": "createdOn", + "displayName": "Created", + "shape": "date" + }, + { + "name": "modifiedOn", + "displayName": "Updated", + "shape": "date" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/accessLogins.json b/plugins/Cloudflare/v1/dataStreams/accessLogins.json new file mode 100644 index 00000000..4d192d74 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/accessLogins.json @@ -0,0 +1,70 @@ +{ + "name": "accessLogins", + "displayName": "Access Logins", + "description": "Daily Zero Trust login attempts for an Access application by identity provider, country and outcome", + "tags": ["Security", "Analytics"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$appId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){accessLoginRequestsAdaptiveGroups(limit:10000,filter:{appId:$appId,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){count dimensions{date identityProvider isSuccessfulLogin country hasWarpEnabled}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "appId": "{{object.rawId}}", + "start": "{{timeframe.start.split('T')[0]}}", + "end": "{{timeframe.end.split('T')[0]}}" + } + }, + "pathToData": "data.viewer.accounts.0.accessLoginRequestsAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare Access Application"] + } + }, + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "dimensions.identityProvider", + "displayName": "Identity Provider", + "shape": "string", + "role": "label" + }, + { + "name": "dimensions.isSuccessfulLogin", + "displayName": "Successful", + "shape": "boolean" + }, + { + "name": "dimensions.country", + "displayName": "Country", + "shape": "string" + }, + { + "name": "dimensions.hasWarpEnabled", + "displayName": "WARP Enabled", + "shape": "boolean" + }, + { + "name": "count", + "displayName": "Logins", + "shape": "number", + "role": "value" + } + ], + "timeframes": ["last7days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/accounts.json b/plugins/Cloudflare/v1/dataStreams/accounts.json new file mode 100644 index 00000000..09d63775 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/accounts.json @@ -0,0 +1,81 @@ +{ + "name": "accounts", + "displayName": "Accounts", + "description": "Cloudflare accounts the API token can access", + "tags": [ + "Account" + ], + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "accounts", + "pathToData": "result", + "expandInnerObjects": true, + "paging": { + "mode": "offset", + "pageSize": { + "realm": "queryArg", + "path": "per_page", + "value": "50" + }, + "offset": { + "mode": "page", + "rowCountIn": { + "realm": "payloadArraySize", + "path": "result" + }, + "base": 1 + }, + "out": { + "realm": "queryArg", + "path": "page" + } + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": "none", + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "id", + "displayName": "Account ID", + "shape": "string", + "role": "id" + }, + { + "name": "name", + "displayName": "Account", + "shape": "string", + "role": "label", + "sourceId": "id", + "sourceType": "Cloudflare Account" + }, + { + "name": "type", + "displayName": "Account Type", + "shape": "string" + }, + { + "name": "created_on", + "displayName": "Created", + "shape": "date" + }, + { + "name": "settings.abuse_contact_email", + "displayName": "Abuse Contact", + "shape": "string" + }, + { + "name": "settings.enforce_twofactor", + "displayName": "Enforce Two-Factor", + "shape": "boolean" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/d1Analytics.json b/plugins/Cloudflare/v1/dataStreams/d1Analytics.json new file mode 100644 index 00000000..797562ef --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/d1Analytics.json @@ -0,0 +1,84 @@ +{ + "name": "d1Analytics", + "displayName": "D1 Queries", + "description": "Daily read and write query counts, rows touched and query latency for a D1 database", + "tags": ["Database", "Analytics"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$databaseId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){d1AnalyticsAdaptiveGroups(limit:10000,filter:{databaseId:$databaseId,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){sum{readQueries writeQueries rowsRead rowsWritten queryBatchResponseBytes}quantiles{queryBatchTimeMsP50 queryBatchTimeMsP90 queryBatchTimeMsP99}dimensions{date}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "databaseId": "{{object.rawId}}", + "start": "{{timeframe.start.split('T')[0]}}", + "end": "{{timeframe.end.split('T')[0]}}" + } + }, + "pathToData": "data.viewer.accounts.0.d1AnalyticsAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare D1 Database"] + } + }, + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "sum.readQueries", + "displayName": "Read Queries", + "shape": "number", + "role": "value" + }, + { + "name": "sum.writeQueries", + "displayName": "Write Queries", + "shape": "number" + }, + { + "name": "sum.rowsRead", + "displayName": "Rows Read", + "shape": "number" + }, + { + "name": "sum.rowsWritten", + "displayName": "Rows Written", + "shape": "number" + }, + { + "name": "sum.queryBatchResponseBytes", + "displayName": "Response Bytes", + "shape": "bytes" + }, + { + "name": "quantiles.queryBatchTimeMsP50", + "displayName": "Query Time P50", + "shape": "milliseconds" + }, + { + "name": "quantiles.queryBatchTimeMsP90", + "displayName": "Query Time P90", + "shape": "milliseconds" + }, + { + "name": "quantiles.queryBatchTimeMsP99", + "displayName": "Query Time P99", + "shape": "milliseconds" + } + ], + "timeframes": ["last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/d1Databases.json b/plugins/Cloudflare/v1/dataStreams/d1Databases.json new file mode 100644 index 00000000..587476be --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/d1Databases.json @@ -0,0 +1,75 @@ +{ + "name": "d1Databases", + "displayName": "D1 Databases", + "description": "D1 SQL databases in a Cloudflare account", + "tags": [ + "Database" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/d1/database", + "postRequestScript": "d1Databases.js", + "paging": { + "mode": "none" + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "databaseName", + "displayName": "Database", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare D1 Database" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "version", + "displayName": "Version", + "shape": "string" + }, + { + "name": "numTables", + "displayName": "Tables", + "shape": "number" + }, + { + "name": "fileSize", + "displayName": "Size", + "shape": "bytes" + }, + { + "name": "createdOn", + "displayName": "Created", + "shape": "date" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/d1Storage.json b/plugins/Cloudflare/v1/dataStreams/d1Storage.json new file mode 100644 index 00000000..1d63e765 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/d1Storage.json @@ -0,0 +1,49 @@ +{ + "name": "d1Storage", + "displayName": "D1 Storage", + "description": "Daily stored size of a D1 database", + "tags": ["Database"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$databaseId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){d1StorageAdaptiveGroups(limit:10000,filter:{databaseId:$databaseId,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){max{databaseSizeBytes}dimensions{date}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "databaseId": "{{object.rawId}}", + "start": "{{timeframe.start.split('T')[0]}}", + "end": "{{timeframe.end.split('T')[0]}}" + } + }, + "pathToData": "data.viewer.accounts.0.d1StorageAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare D1 Database"] + } + }, + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "max.databaseSizeBytes", + "displayName": "Database Size", + "shape": "bytes", + "role": "value" + } + ], + "timeframes": ["last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/durableObjectInvocations.json b/plugins/Cloudflare/v1/dataStreams/durableObjectInvocations.json new file mode 100644 index 00000000..fb565df8 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/durableObjectInvocations.json @@ -0,0 +1,110 @@ +{ + "name": "durableObjectInvocations", + "displayName": "Durable Object Invocations", + "description": "Request, error and wall time metrics for a Durable Object namespace", + "tags": ["Workers", "Analytics"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$namespaceId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){durableObjectsInvocationsAdaptiveGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){sum{requests errors responseBodySize wallTime}quantiles{wallTimeP50 wallTimeP90 wallTimeP99}dimensions{datetime status}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "namespaceId": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "pathToData": "data.viewer.accounts.0.durableObjectsInvocationsAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare Durable Object Namespace"] + } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "sum.requests", + "displayName": "Requests", + "shape": "number", + "role": "value" + }, + { + "name": "sum.errors", + "displayName": "Errors", + "shape": "number" + }, + { + "name": "sum.responseBodySize", + "displayName": "Response Body Size", + "shape": "bytes" + }, + { + "name": "quantiles.wallTimeP50", + "displayName": "Wall Time P50 (raw)", + "shape": "number", + "visible": false + }, + { + "name": "wallTimeP50Ms", + "displayName": "Wall Time P50", + "computed": true, + "valueExpression": "{{ Number($['quantiles.wallTimeP50']) / 1000 }}", + "shape": ["milliseconds", { "decimalPlaces": 2 }] + }, + { + "name": "quantiles.wallTimeP90", + "displayName": "Wall Time P90 (raw)", + "shape": "number", + "visible": false + }, + { + "name": "wallTimeP90Ms", + "displayName": "Wall Time P90", + "computed": true, + "valueExpression": "{{ Number($['quantiles.wallTimeP90']) / 1000 }}", + "shape": ["milliseconds", { "decimalPlaces": 2 }] + }, + { + "name": "quantiles.wallTimeP99", + "displayName": "Wall Time P99 (raw)", + "shape": "number", + "visible": false + }, + { + "name": "wallTimeP99Ms", + "displayName": "Wall Time P99", + "computed": true, + "valueExpression": "{{ Number($['quantiles.wallTimeP99']) / 1000 }}", + "shape": ["milliseconds", { "decimalPlaces": 2 }] + }, + { + "name": "dimensions.status", + "displayName": "Status", + "shape": "string" + }, + { + "name": "errorRate", + "displayName": "Error Rate", + "computed": true, + "valueExpression": "{{ Number($['sum.requests']) > 0 ? Math.round(10000 * Number($['sum.errors']) / Number($['sum.requests'])) / 100 : 0 }}", + "shape": ["percent", { "decimalPlaces": 2 }] + } + ], + "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/durableObjectNamespaces.json b/plugins/Cloudflare/v1/dataStreams/durableObjectNamespaces.json new file mode 100644 index 00000000..1a09ec93 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/durableObjectNamespaces.json @@ -0,0 +1,88 @@ +{ + "name": "durableObjectNamespaces", + "displayName": "Durable Object Namespaces", + "description": "Durable Object namespaces defined in a Cloudflare account", + "tags": [ + "Workers", + "Storage" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/workers/durable_objects/namespaces", + "postRequestScript": "durableObjectNamespaces.js", + "paging": { + "mode": "offset", + "pageSize": { + "realm": "queryArg", + "path": "per_page", + "value": "100" + }, + "offset": { + "mode": "page", + "rowCountIn": { + "realm": "payloadArraySize", + "path": "result" + }, + "base": 1 + }, + "out": { + "realm": "queryArg", + "path": "page" + } + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "namespaceName", + "displayName": "Namespace", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare Durable Object Namespace" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "scriptName", + "displayName": "Worker", + "shape": "string" + }, + { + "name": "className", + "displayName": "Class", + "shape": "string" + }, + { + "name": "usesSqlite", + "displayName": "SQLite Backed", + "shape": "boolean" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/durableObjectStorage.json b/plugins/Cloudflare/v1/dataStreams/durableObjectStorage.json new file mode 100644 index 00000000..f8eb0f41 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/durableObjectStorage.json @@ -0,0 +1,49 @@ +{ + "name": "durableObjectStorage", + "displayName": "Durable Object Storage", + "description": "Daily stored size of a Durable Object namespace's SQLite storage", + "tags": ["Workers", "Storage"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$namespaceId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){durableObjectsSqlStorageGroups(limit:10000,filter:{namespaceId:$namespaceId,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){max{storedBytes}dimensions{date}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "namespaceId": "{{object.rawId}}", + "start": "{{timeframe.start.split('T')[0]}}", + "end": "{{timeframe.end.split('T')[0]}}" + } + }, + "pathToData": "data.viewer.accounts.0.durableObjectsSqlStorageGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare Durable Object Namespace"] + } + }, + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "max.storedBytes", + "displayName": "Storage Size", + "shape": "bytes", + "role": "value" + } + ], + "timeframes": ["last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/gatewayDnsQueries.json b/plugins/Cloudflare/v1/dataStreams/gatewayDnsQueries.json new file mode 100644 index 00000000..63d93def --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/gatewayDnsQueries.json @@ -0,0 +1,64 @@ +{ + "name": "gatewayDnsQueries", + "displayName": "Gateway DNS Queries", + "description": "DNS query counts for Zero Trust Gateway grouped by a selectable dimension", + "tags": ["Security", "DNS"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayResolverQueriesAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date {{breakdown}} }}}}}", + "variables": { + "accountTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "gatewayDnsQueries.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Account"] } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "resolverDecision", + "options": [ + { "value": "resolverDecision", "label": "Decision" }, + { "value": "categoryNames", "label": "Category" }, + { "value": "locationName", "label": "Location" }, + { "value": "resourceRecordTypes", "label": "Query Type" } + ] + } + ], + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "queryCount", + "displayName": "Query Count", + "shape": "number", + "role": "value" + } + ], + "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/gatewayHttpRequests.json b/plugins/Cloudflare/v1/dataStreams/gatewayHttpRequests.json new file mode 100644 index 00000000..c4aece5f --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/gatewayHttpRequests.json @@ -0,0 +1,66 @@ +{ + "name": "gatewayHttpRequests", + "displayName": "Gateway HTTP Requests", + "description": "Zero Trust Gateway HTTP request counts for an account grouped by a selectable dimension", + "tags": ["Security", "Network"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayL7RequestsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count dimensions{date {{breakdown}} }}}}}", + "variables": { + "accountTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "gatewayHttpRequests.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Account"] } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "action", + "options": [ + { "value": "action", "label": "Action" }, + { "value": "httpHost", "label": "Host" }, + { "value": "categoryNames", "label": "Category" }, + { "value": "httpStatusCode", "label": "Status Code" }, + { "value": "email", "label": "User" }, + { "value": "deviceId", "label": "Device" } + ] + } + ], + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "requests", + "displayName": "Requests", + "shape": "number", + "role": "value" + } + ], + "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/graphqlQuery.json b/plugins/Cloudflare/v1/dataStreams/graphqlQuery.json new file mode 100644 index 00000000..a0e8c790 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/graphqlQuery.json @@ -0,0 +1,69 @@ +{ + "name": "graphqlQuery", + "displayName": "GraphQL Query", + "description": "Rows returned by a user-supplied Cloudflare GraphQL Analytics query", + "tags": [ + "Analytics" + ], + "baseDataSourceName": "httpRequestUnscoped", + "manualConfigApply": true, + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "{{query}}", + "variables": "{{ Object.assign(typeof timeframe !== 'undefined' && timeframe && timeframe.start ? { start: timeframe.start, end: timeframe.end, startDate: timeframe.start.split('T')[0], endDate: timeframe.end.split('T')[0] } : {}, typeof variables === 'string' ? JSON.parse(variables || '{}') : (variables || {})) }}" + }, + "postRequestScript": "graphqlQuery.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": "none", + "ui": [ + { + "type": "code", + "name": "query", + "label": "GraphQL query", + "language": "graphql", + "help": "A query for the Cloudflare GraphQL Analytics API. These variables are always sent and can be declared in the query: `$start` / `$end` (`Time!`, ISO 8601, the selected timeframe) and `$startDate` / `$endDate` (`Date!`, `YYYY-MM-DD`). Cloudflare's scalar names are case sensitive - `string!` is lower case, `Time!` and `Date!` are not. Each analytics node has its own maximum query window and retention (as little as 1 day on some nodes), which is why only short timeframes are offered - for a longer or fixed window, select the **None** timeframe and write the dates into the query's own filter. See the [Cloudflare GraphQL Analytics docs](https://developers.cloudflare.com/analytics/graphql-api/).", + "defaultValue": "query ($start: Time!, $end: Time!) {\n viewer {\n zones(limit: 1) {\n httpRequests1hGroups(\n limit: 1000\n filter: { datetime_geq: $start, datetime_leq: $end }\n orderBy: [datetime_ASC]\n ) {\n dimensions {\n datetime\n }\n sum {\n requests\n bytes\n cachedRequests\n threats\n }\n uniq {\n uniques\n }\n }\n }\n }\n}", + "validation": { + "required": true + } + }, + { + "type": "code", + "name": "variables", + "label": "Variables", + "language": "json", + "help": "Extra GraphQL variables as a JSON object, for example `{ \"zoneTag\": \"\" }` or `{ \"accountTag\": \"\" }`. These are merged with the built-in `start`, `end`, `startDate` and `endDate` variables; a value set here of the same name wins.", + "defaultValue": {} + }, + { + "type": "text", + "name": "pathToData", + "label": "Path to rows", + "placeholder": "data.viewer.zones.0.httpRequests1hGroups", + "help": "Dot path to the array of rows in the query response, for example `data.viewer.zones.0.httpRequests1hGroups`. Nested fields in each row become dot-notation columns such as `sum.requests`. If the path is wrong, the error lists the array paths the response actually contains.", + "defaultValue": "data.viewer.zones.0.httpRequests1hGroups", + "validation": { + "required": true + } + } + ], + "metadata": [ + { + "pattern": ".*" + } + ], + "supportsNoneTimeframe": true, + "timeframes": [ + "none", + "last1hour", + "last12hours", + "last24hours" + ] +} diff --git a/plugins/Cloudflare/v1/dataStreams/hyperdriveConfigs.json b/plugins/Cloudflare/v1/dataStreams/hyperdriveConfigs.json new file mode 100644 index 00000000..4f77d86f --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/hyperdriveConfigs.json @@ -0,0 +1,48 @@ +{ + "name": "hyperdriveConfigs", + "displayName": "Hyperdrive Configs", + "description": "Hyperdrive database connection configurations in a Cloudflare account", + "tags": ["Database"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/hyperdrive/configs", + "postRequestScript": "hyperdriveConfigs.js", + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Account"] } + }, + "visibility": { "type": "hidden" }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "configName", + "displayName": "Config", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare Hyperdrive Config" + }, + { "name": "accountId", "displayName": "Account ID", "shape": "string" }, + { "name": "database", "displayName": "Database", "shape": "string" }, + { "name": "host", "displayName": "Host", "shape": "string" }, + { "name": "scheme", "displayName": "Scheme", "shape": "string" }, + { + "name": "cachingDisabled", + "displayName": "Caching Disabled", + "shape": "boolean" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/hyperdriveQueries.json b/plugins/Cloudflare/v1/dataStreams/hyperdriveQueries.json new file mode 100644 index 00000000..b145e172 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/hyperdriveQueries.json @@ -0,0 +1,54 @@ +{ + "name": "hyperdriveQueries", + "displayName": "Hyperdrive Queries", + "description": "Daily query count and query latency for a Hyperdrive config", + "tags": ["Database", "Analytics"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$configId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){hyperdriveQueriesAdaptiveGroups(limit:10000,filter:{configId:$configId,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){count avg{queryLatency} dimensions{date}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "configId": "{{object.rawId}}", + "start": "{{timeframe.start.split('T')[0]}}", + "end": "{{timeframe.end.split('T')[0]}}" + } + }, + "pathToData": "data.viewer.accounts.0.hyperdriveQueriesAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare Hyperdrive Config"] + } + }, + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "count", + "displayName": "Queries", + "shape": "number", + "role": "value" + }, + { + "name": "avg.queryLatency", + "displayName": "Avg Query Latency", + "shape": "milliseconds" + } + ], + "timeframes": ["last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/kvNamespaces.json b/plugins/Cloudflare/v1/dataStreams/kvNamespaces.json new file mode 100644 index 00000000..817a6c6f --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/kvNamespaces.json @@ -0,0 +1,77 @@ +{ + "name": "kvNamespaces", + "displayName": "KV Namespaces", + "description": "Workers KV namespaces in a Cloudflare account", + "tags": [ + "Storage" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/storage/kv/namespaces", + "postRequestScript": "kvNamespaces.js", + "paging": { + "mode": "offset", + "pageSize": { + "realm": "queryArg", + "path": "per_page", + "value": "100" + }, + "offset": { + "mode": "page", + "rowCountIn": { + "realm": "payloadArraySize", + "path": "result" + }, + "base": 1 + }, + "out": { + "realm": "queryArg", + "path": "page" + } + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "namespaceTitle", + "displayName": "Namespace", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare KV Namespace" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "supportsUrlEncoding", + "displayName": "Supports URL Encoding", + "shape": "boolean" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/kvOperations.json b/plugins/Cloudflare/v1/dataStreams/kvOperations.json new file mode 100644 index 00000000..50ef33d1 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/kvOperations.json @@ -0,0 +1,66 @@ +{ + "name": "kvOperations", + "displayName": "KV Operations", + "description": "Daily read, write, delete and list operation counts and latency for a Workers KV namespace", + "tags": ["Storage", "Analytics"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$namespaceId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){kvOperationsAdaptiveGroups(limit:10000,filter:{namespaceId:$namespaceId,date_geq:$start,date_leq:$end},orderBy:[date_DESC]){sum{requests}dimensions{date actionType}quantiles{latencyMsP50 latencyMsP90 latencyMsP99}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "namespaceId": "{{object.rawId}}", + "start": "{{timeframe.start.split('T')[0]}}", + "end": "{{timeframe.end.split('T')[0]}}" + } + }, + "pathToData": "data.viewer.accounts.0.kvOperationsAdaptiveGroups", + "expandInnerObjects": true, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare KV Namespace"] } + }, + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "dimensions.actionType", + "displayName": "Operation", + "shape": "string", + "role": "label" + }, + { + "name": "sum.requests", + "displayName": "Requests", + "shape": "number", + "role": "value" + }, + { + "name": "quantiles.latencyMsP50", + "displayName": "Latency P50", + "shape": "milliseconds" + }, + { + "name": "quantiles.latencyMsP90", + "displayName": "Latency P90", + "shape": "milliseconds" + }, + { + "name": "quantiles.latencyMsP99", + "displayName": "Latency P99", + "shape": "milliseconds" + } + ], + "timeframes": ["last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/kvStorage.json b/plugins/Cloudflare/v1/dataStreams/kvStorage.json new file mode 100644 index 00000000..98aba56d --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/kvStorage.json @@ -0,0 +1,50 @@ +{ + "name": "kvStorage", + "displayName": "KV Storage", + "description": "Daily stored key count and byte size for a Workers KV namespace", + "tags": ["Storage"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$namespaceId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){kvStorageAdaptiveGroups(filter:{namespaceId:$namespaceId,date_geq:$start,date_leq:$end},limit:10000,orderBy:[date_DESC]){max{keyCount byteCount}dimensions{date}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "namespaceId": "{{object.rawId}}", + "start": "{{timeframe.start.split('T')[0]}}", + "end": "{{timeframe.end.split('T')[0]}}" + } + }, + "pathToData": "data.viewer.accounts.0.kvStorageAdaptiveGroups", + "expandInnerObjects": true, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare KV Namespace"] } + }, + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "max.keyCount", + "displayName": "Keys", + "shape": "number", + "role": "value" + }, + { + "name": "max.byteCount", + "displayName": "Size", + "shape": "bytes" + } + ], + "timeframes": ["last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/loadBalancerPoolHealth.json b/plugins/Cloudflare/v1/dataStreams/loadBalancerPoolHealth.json new file mode 100644 index 00000000..a7f16b7c --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/loadBalancerPoolHealth.json @@ -0,0 +1,79 @@ +{ + "name": "loadBalancerPoolHealth", + "displayName": "Load Balancer Pool Health", + "description": "Per-origin health, response time and failure reason for a load balancer pool at each Cloudflare edge location", + "tags": ["Network", "Availability"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.accountId}}/load_balancers/pools/{{object.rawId}}/health", + "postRequestScript": "loadBalancerPoolHealth.js", + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare Load Balancer Pool"] + } + }, + "metadata": [ + { + "name": "colo", + "displayName": "Location", + "shape": "string", + "role": "label" + }, + { + "name": "origin", + "displayName": "Origin", + "shape": "string" + }, + { + "name": "healthy", + "displayName": "Healthy", + "shape": "boolean", + "role": "value" + }, + { + "name": "health", + "displayName": "Health", + "computed": true, + "valueExpression": "{{ $['healthy'] ? 'Healthy' : 'Unhealthy' }}", + "shape": [ + "state", + { + "map": { + "success": ["Healthy"], + "error": ["Unhealthy"] + } + } + ] + }, + { + "name": "responseCode", + "displayName": "Response Code", + "shape": "number" + }, + { + "name": "rtt", + "displayName": "Response Time", + "shape": "string" + }, + { + "name": "failureReason", + "displayName": "Failure Reason", + "shape": "string" + }, + { + "name": "coloHealthy", + "displayName": "Location Healthy", + "shape": "boolean" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/loadBalancerPools.json b/plugins/Cloudflare/v1/dataStreams/loadBalancerPools.json new file mode 100644 index 00000000..fb89b7b7 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/loadBalancerPools.json @@ -0,0 +1,85 @@ +{ + "name": "loadBalancerPools", + "displayName": "Load Balancer Pools", + "description": "Load balancer origin pools in a Cloudflare account", + "tags": [ + "Network" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/load_balancers/pools", + "postRequestScript": "loadBalancerPools.js", + "paging": { + "mode": "none" + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "poolName", + "displayName": "Pool", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare Load Balancer Pool" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "enabled", + "displayName": "Enabled", + "shape": "boolean" + }, + { + "name": "originCount", + "displayName": "Origins", + "shape": "number" + }, + { + "name": "minimumOrigins", + "displayName": "Minimum Origins", + "shape": "number" + }, + { + "name": "monitorId", + "displayName": "Monitor", + "shape": "string" + }, + { + "name": "createdOn", + "displayName": "Created", + "shape": "date" + }, + { + "name": "modifiedOn", + "displayName": "Modified", + "shape": "date" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/pagesDeployments.json b/plugins/Cloudflare/v1/dataStreams/pagesDeployments.json new file mode 100644 index 00000000..366ec552 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/pagesDeployments.json @@ -0,0 +1,102 @@ +{ + "name": "pagesDeployments", + "displayName": "Pages Deployments", + "description": "Deployment history for a Cloudflare Pages project including branch, commit and status", + "tags": [ + "Pages", + "CI/CD" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.accountId}}/pages/projects/{{object.name}}/deployments", + "postRequestScript": "pagesDeployments.js", + "paging": { + "mode": "offset", + "pageSize": { + "realm": "queryArg", + "path": "per_page", + "value": "10" + }, + "offset": { + "mode": "page", + "rowCountIn": { "realm": "payloadArraySize", "path": "result" }, + "base": 1 + }, + "out": { "realm": "queryArg", "path": "page" } + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Pages Project" + ] + } + }, + "metadata": [ + { + "name": "short_id", + "displayName": "Deployment", + "shape": "string", + "role": "label" + }, + { + "name": "environment", + "displayName": "Environment", + "shape": "string" + }, + { + "name": "status", + "displayName": "Status", + "shape": [ + "state", + { + "map": { + "success": ["success"], + "error": ["failure", "canceled"], + "warning": ["skipped", "active", "building", "queued"], + "unknown": ["idle"] + } + } + ] + }, + { + "name": "stage", + "displayName": "Stage", + "shape": "string" + }, + { + "name": "url", + "displayName": "URL", + "shape": "url" + }, + { + "name": "branch", + "displayName": "Branch", + "shape": "string" + }, + { + "name": "commit", + "displayName": "Commit", + "shape": "string" + }, + { + "name": "commitMessage", + "displayName": "Commit Message", + "shape": "string" + }, + { + "name": "created_on", + "displayName": "Created", + "shape": "date", + "role": "timestamp" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/pagesProjects.json b/plugins/Cloudflare/v1/dataStreams/pagesProjects.json new file mode 100644 index 00000000..ebc6bdde --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/pagesProjects.json @@ -0,0 +1,121 @@ +{ + "name": "pagesProjects", + "displayName": "Pages Projects", + "description": "Cloudflare Pages projects in an account with their production branch and latest deployment", + "tags": [ + "Pages" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/pages/projects", + "postRequestScript": "pagesProjects.js", + "paging": { + "mode": "offset", + "pageSize": { + "realm": "queryArg", + "path": "per_page", + "value": "10" + }, + "offset": { + "mode": "page", + "rowCountIn": { + "realm": "payloadArraySize", + "path": "result" + }, + "base": 1 + }, + "out": { + "realm": "queryArg", + "path": "page" + } + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "projectName", + "displayName": "Project", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare Pages Project" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "subdomain", + "displayName": "Subdomain", + "shape": "string" + }, + { + "name": "domains", + "displayName": "Domains", + "shape": "string" + }, + { + "name": "productionBranch", + "displayName": "Production Branch", + "shape": "string" + }, + { + "name": "latestDeploymentStatus", + "displayName": "Latest Deployment", + "shape": [ + "state", + { + "map": { + "success": [ + "success" + ], + "error": [ + "failure", + "canceled" + ], + "warning": [ + "idle", + "active", + "queued", + "building" + ] + } + } + ] + }, + { + "name": "latestDeploymentOn", + "displayName": "Last Deployed", + "shape": "date" + }, + { + "name": "createdOn", + "displayName": "Created", + "shape": "date" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/queueBacklog.json b/plugins/Cloudflare/v1/dataStreams/queueBacklog.json new file mode 100644 index 00000000..1c9a03ac --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/queueBacklog.json @@ -0,0 +1,51 @@ +{ + "name": "queueBacklog", + "displayName": "Queue Backlog", + "description": "Average number of messages and bytes waiting in a queue over time", + "tags": ["Queues"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$queueId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){queueBacklogAdaptiveGroups(limit:10000,filter:{queueId:$queueId,datetime_geq:$start,datetime_leq:$end},orderBy:[datetimeHour_ASC]){avg{messages bytes}dimensions{datetimeHour}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "queueId": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "pathToData": "data.viewer.accounts.0.queueBacklogAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Queue"] } + }, + "metadata": [ + { + "name": "dimensions.datetimeHour", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "avg.messages", + "displayName": "Messages Backlogged", + "shape": ["number", { "decimalPlaces": 1 }], + "role": "value" + }, + { + "name": "avg.bytes", + "displayName": "Backlog Size", + "shape": "bytes" + } + ], + "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/queueMessageOperations.json b/plugins/Cloudflare/v1/dataStreams/queueMessageOperations.json new file mode 100644 index 00000000..718141fc --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/queueMessageOperations.json @@ -0,0 +1,95 @@ +{ + "name": "queueMessageOperations", + "displayName": "Queue Message Operations", + "description": "Message write, read and delete operations on a queue with their outcome and lag time", + "tags": ["Queues", "Analytics"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$queueId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){queueMessageOperationsAdaptiveGroups(limit:10000,filter:{queueId:$queueId,datetime_geq:$start,datetime_leq:$end},orderBy:[datetimeHour_ASC]){count sum{billableOperations bytes}avg{lagTime retryCount}max{messageSize}dimensions{datetimeHour actionType outcome consumerType}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "queueId": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "pathToData": "data.viewer.accounts.0.queueMessageOperationsAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Queue"] } + }, + "metadata": [ + { + "name": "dimensions.datetimeHour", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "dimensions.actionType", + "displayName": "Operation", + "shape": "string", + "role": "label" + }, + { + "name": "dimensions.outcome", + "displayName": "Outcome", + "shape": [ + "state", + { + "map": { + "success": ["success"], + "error": ["fail", "dlq"] + } + } + ] + }, + { + "name": "dimensions.consumerType", + "displayName": "Consumer Type", + "shape": "string" + }, + { + "name": "count", + "displayName": "Operations", + "shape": "number", + "role": "value" + }, + { + "name": "sum.billableOperations", + "displayName": "Billable Operations", + "shape": "number" + }, + { + "name": "sum.bytes", + "displayName": "Bytes", + "shape": "bytes" + }, + { + "name": "avg.lagTime", + "displayName": "Lag Time", + "shape": "milliseconds" + }, + { + "name": "avg.retryCount", + "displayName": "Avg Retries", + "shape": ["number", { "decimalPlaces": 2 }] + }, + { + "name": "max.messageSize", + "displayName": "Max Message Size", + "shape": "bytes" + } + ], + "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/queues.json b/plugins/Cloudflare/v1/dataStreams/queues.json new file mode 100644 index 00000000..ca9cfc11 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/queues.json @@ -0,0 +1,80 @@ +{ + "name": "queues", + "displayName": "Queues", + "description": "Cloudflare Queues in an account with their producer and consumer counts", + "tags": [ + "Queues" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/queues", + "postRequestScript": "queues.js", + "paging": { + "mode": "none" + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "queueName", + "displayName": "Queue", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare Queue" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "producers", + "displayName": "Producers", + "shape": "number" + }, + { + "name": "consumers", + "displayName": "Consumers", + "shape": "number" + }, + { + "name": "createdOn", + "displayName": "Created", + "shape": "date" + }, + { + "name": "modifiedOn", + "displayName": "Modified", + "shape": "date" + }, + { + "name": "consumerScripts", + "displayName": "Consumer Workers", + "shape": "string" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/r2Buckets.json b/plugins/Cloudflare/v1/dataStreams/r2Buckets.json new file mode 100644 index 00000000..1c37cdf6 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/r2Buckets.json @@ -0,0 +1,70 @@ +{ + "name": "r2Buckets", + "displayName": "R2 Buckets", + "description": "R2 object storage buckets in a Cloudflare account", + "tags": [ + "Storage" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/r2/buckets", + "postRequestScript": "r2Buckets.js", + "paging": { + "mode": "none" + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "bucketName", + "displayName": "Bucket", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare R2 Bucket" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "location", + "displayName": "Location", + "shape": "string" + }, + { + "name": "storageClass", + "displayName": "Storage Class", + "shape": "string" + }, + { + "name": "createdOn", + "displayName": "Created", + "shape": "date" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/r2Operations.json b/plugins/Cloudflare/v1/dataStreams/r2Operations.json new file mode 100644 index 00000000..90fe40ea --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/r2Operations.json @@ -0,0 +1,62 @@ +{ + "name": "r2Operations", + "displayName": "R2 Operations", + "description": "Requests and response bytes against an R2 bucket, broken down by operation and outcome", + "tags": ["Storage", "Analytics"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$bucketName:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){r2OperationsAdaptiveGroups(limit:10000,filter:{bucketName:$bucketName,datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){sum{requests responseBytes}dimensions{datetime actionType actionStatus}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "bucketName": "{{object.name}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "pathToData": "data.viewer.accounts.0.r2OperationsAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare R2 Bucket"] } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "dimensions.actionType", + "displayName": "Operation", + "shape": "string", + "role": "label" + }, + { + "name": "dimensions.actionStatus", + "displayName": "Outcome", + "shape": "string" + }, + { + "name": "sum.requests", + "displayName": "Requests", + "shape": "number", + "role": "value" + }, + { + "name": "sum.responseBytes", + "displayName": "Response Bytes", + "shape": "bytes" + } + ], + "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/r2Storage.json b/plugins/Cloudflare/v1/dataStreams/r2Storage.json new file mode 100644 index 00000000..370b7029 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/r2Storage.json @@ -0,0 +1,61 @@ +{ + "name": "r2Storage", + "displayName": "R2 Storage", + "description": "Stored object count and payload size for an R2 bucket over time", + "tags": ["Storage"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$bucketName:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){r2StorageAdaptiveGroups(limit:10000,filter:{bucketName:$bucketName,datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){max{objectCount payloadSize metadataSize uploadCount}dimensions{datetime}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "bucketName": "{{object.name}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "pathToData": "data.viewer.accounts.0.r2StorageAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare R2 Bucket"] } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "max.payloadSize", + "displayName": "Payload Size", + "shape": "bytes", + "role": "value" + }, + { + "name": "max.metadataSize", + "displayName": "Metadata Size", + "shape": "bytes" + }, + { + "name": "max.objectCount", + "displayName": "Objects", + "shape": "number" + }, + { + "name": "max.uploadCount", + "displayName": "Uploads", + "shape": "number" + } + ], + "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/rumPageLoads.json b/plugins/Cloudflare/v1/dataStreams/rumPageLoads.json new file mode 100644 index 00000000..b5b46ebe --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/rumPageLoads.json @@ -0,0 +1,71 @@ +{ + "name": "rumPageLoads", + "displayName": "Web Analytics Page Loads", + "description": "Page load and visit counts for a zone's Web Analytics (RUM) traffic grouped by a selectable dimension", + "tags": ["Zone", "Analytics"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$requestHost:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumPageloadEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end,requestHost_like:$requestHost},orderBy:[count_DESC]){count sum{visits} dimensions{date {{breakdown}} }}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}", + "requestHost": "{{'%' + object.name}}" + } + }, + "postRequestScript": "rumPageLoads.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "countryName", + "options": [ + { "value": "countryName", "label": "Country" }, + { "value": "deviceType", "label": "Device Type" }, + { "value": "userAgentBrowser", "label": "Browser" }, + { "value": "refererHost", "label": "Referer Host" }, + { "value": "requestPath", "label": "Path" } + ] + } + ], + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "pageViews", + "displayName": "Page Views", + "shape": "number", + "role": "value" + }, + { + "name": "visits", + "displayName": "Visits", + "shape": "number" + } + ], + "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/rumWebVitals.json b/plugins/Cloudflare/v1/dataStreams/rumWebVitals.json new file mode 100644 index 00000000..226dac19 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/rumWebVitals.json @@ -0,0 +1,82 @@ +{ + "name": "rumWebVitals", + "displayName": "Core Web Vitals", + "description": "Daily P75 Core Web Vitals (LCP, INP/FID, CLS) and RUM sample counts for a zone's hostnames", + "tags": ["Zone", "Analytics"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$hostFilter:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumWebVitalsEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end,requestHost_like:$hostFilter},orderBy:[date_ASC]){count dimensions{date} quantiles{largestContentfulPaintP75 interactionToNextPaintP75 firstInputDelayP75 cumulativeLayoutShiftP75}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}", + "hostFilter": "{{'%' + object.name}}" + } + }, + "expandInnerObjects": true, + "pathToData": "data.viewer.accounts.0.rumWebVitalsEventsAdaptiveGroups", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "quantiles.largestContentfulPaintP75", + "visible": false + }, + { + "name": "largestContentfulPaintP75", + "displayName": "Largest Contentful Paint (P75)", + "computed": true, + "valueExpression": "{{ Number($['quantiles.largestContentfulPaintP75']) < 0 ? null : Math.round(Number($['quantiles.largestContentfulPaintP75']) / 1000) }}", + "shape": "milliseconds", + "role": "value" + }, + { + "name": "quantiles.interactionToNextPaintP75", + "visible": false + }, + { + "name": "quantiles.firstInputDelayP75", + "visible": false + }, + { + "name": "interactionToNextPaintP75", + "displayName": "Interaction to Next Paint (P75)", + "computed": true, + "valueExpression": "{{ Number($['quantiles.interactionToNextPaintP75']) >= 0 ? Math.round(Number($['quantiles.interactionToNextPaintP75']) / 1000) : (Number($['quantiles.firstInputDelayP75']) >= 0 ? Math.round(Number($['quantiles.firstInputDelayP75']) / 1000) : null) }}", + "shape": "milliseconds" + }, + { + "name": "quantiles.cumulativeLayoutShiftP75", + "visible": false + }, + { + "name": "cumulativeLayoutShiftP75", + "displayName": "Cumulative Layout Shift (P75)", + "computed": true, + "valueExpression": "{{ Number($['quantiles.cumulativeLayoutShiftP75']) < 0 ? null : Number($['quantiles.cumulativeLayoutShiftP75']) }}", + "shape": ["number", { "decimalPlaces": 3 }] + }, + { + "name": "count", + "displayName": "Samples", + "shape": "number" + } + ], + "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/accessApps.js b/plugins/Cloudflare/v1/dataStreams/scripts/accessApps.js new file mode 100644 index 00000000..4846636d --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/accessApps.js @@ -0,0 +1,16 @@ +// Stamps the account id from the scoped object onto every row so the Access +// analytics stream can build its account-scoped GraphQL query. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((app) => ({ + sourceId: app.id || app.uid, + appName: app.name, + accountId: accountId, + domain: app.domain || "", + appType: app.type || "", + sessionDuration: app.session_duration || "", + appLauncherVisible: Boolean(app.app_launcher_visible), + createdOn: app.created_at, + modifiedOn: app.updated_at, +})); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/d1Databases.js b/plugins/Cloudflare/v1/dataStreams/scripts/d1Databases.js new file mode 100644 index 00000000..39edabbd --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/d1Databases.js @@ -0,0 +1,14 @@ +// Stamps the account id from the scoped object onto every row so downstream +// D1 analytics streams can build their account-scoped GraphQL query. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((db) => ({ + sourceId: db.uuid, + databaseName: db.name, + accountId: accountId, + version: db.version || "", + numTables: typeof db.num_tables === "number" ? db.num_tables : null, + fileSize: typeof db.file_size === "number" ? db.file_size : null, + createdOn: db.created_at, +})); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/durableObjectNamespaces.js b/plugins/Cloudflare/v1/dataStreams/scripts/durableObjectNamespaces.js new file mode 100644 index 00000000..86c01155 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/durableObjectNamespaces.js @@ -0,0 +1,14 @@ +// Stamps the account id from the scoped object onto every row so the Durable +// Object analytics streams can build their account-scoped GraphQL query, and +// exposes the owning Worker script name as a correlation join key. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((ns) => ({ + sourceId: ns.id, + namespaceName: ns.name || ns.id, + accountId: accountId, + scriptName: ns.script || "", + className: ns.class || "", + usesSqlite: Boolean(ns.use_sqlite), +})); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/gatewayDnsQueries.js b/plugins/Cloudflare/v1/dataStreams/scripts/gatewayDnsQueries.js new file mode 100644 index 00000000..93b2155b --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/gatewayDnsQueries.js @@ -0,0 +1,32 @@ +// dataStreams/scripts/gatewayDnsQueries.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the dimension value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.resolverDecision vs dimensions.categoryNames vs ...). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.accounts && + data.data.viewer.accounts[0] && + data.data.viewer.accounts[0].gatewayResolverQueriesAdaptiveGroups) || + []; + +result = groups.map((row) => { + const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; + const label = + rawValue === undefined || rawValue === null || rawValue === "" || (Array.isArray(rawValue) && rawValue.length === 0) + ? "Unknown" + : Array.isArray(rawValue) + ? rawValue.join(", ") + : String(rawValue); + + return { + date: row.dimensions && row.dimensions.date, + breakdown: label, + queryCount: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0 + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/gatewayHttpRequests.js b/plugins/Cloudflare/v1/dataStreams/scripts/gatewayHttpRequests.js new file mode 100644 index 00000000..e27fafda --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/gatewayHttpRequests.js @@ -0,0 +1,27 @@ +// dataStreams/scripts/gatewayHttpRequests.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the dimension value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.action vs dimensions.httpHost vs ...). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.accounts && + data.data.viewer.accounts[0] && + data.data.viewer.accounts[0].gatewayL7RequestsAdaptiveGroups) || + []; + +result = groups.map((row) => { + const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; + const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); + + return { + date: row.dimensions && row.dimensions.date, + breakdown: label, + requests: Number((row.count !== undefined && row.count !== null ? row.count : 0)) || 0 + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/graphqlQuery.js b/plugins/Cloudflare/v1/dataStreams/scripts/graphqlQuery.js new file mode 100644 index 00000000..da1ba865 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/graphqlQuery.js @@ -0,0 +1,88 @@ +// A post-request script is required for this stream (unusually - most streams should +// use pathToData instead) for two reasons that can't be expressed declaratively: +// 1. The row location is chosen by the user per tile. `config.pathToData` is a single +// static string baked into the stream, so it cannot follow a path that changes with +// the query; only a script can read the user's value from `context.config`. +// 2. Cloudflare answers a failed GraphQL query with HTTP 200 and a populated `errors` +// array, so the request never looks like a failure and `errorHandling` never fires. +// Without this script a broken query silently shapes to zero rows. +// It also flattens the nested GraphQL group shape (dimensions/sum/avg/uniq/quantiles) +// into dot-notation columns, matching the other Cloudflare analytics streams. + +const body = data || {}; + +const graphqlErrors = Array.isArray(body.errors) ? body.errors : []; +if (graphqlErrors.length) { + const messages = graphqlErrors + .map((e) => (e && e.message) || JSON.stringify(e)) + .filter(Boolean); + throw new Error('Cloudflare GraphQL error: ' + messages.join(' | ')); +} + +// Every array in the response, as a dot path - used to make path errors actionable. +const arrayPaths = (node, prefix, depth, found) => { + if (depth > 6 || node === null || typeof node !== 'object') return found; + if (Array.isArray(node)) { + if (prefix) found.push(prefix); + if (node.length) arrayPaths(node[0], prefix + '.0', depth + 1, found); + return found; + } + for (const key of Object.keys(node)) { + arrayPaths(node[key], prefix ? prefix + '.' + key : key, depth + 1, found); + } + return found; +}; + +const candidates = () => { + const paths = arrayPaths(body, '', 0, []); + return paths.length + ? ' Arrays available in this response: ' + paths.join(', ') + : ' This response contains no arrays.'; +}; + +const walk = (root, path) => + path + .split('.') + .filter((segment) => segment.length) + .reduce( + (node, key) => (node === null || node === undefined ? undefined : node[key]), + root + ); + +const requestedPath = String( + (context && context.config && context.config.pathToData) || '' +).trim(); + +if (!requestedPath) { + throw new Error('Set "Path to rows" to the path of the array of rows in the query response.' + candidates()); +} + +// Tolerate a path written with or without the leading `data.` envelope. +let rows = walk(body, requestedPath); +if (rows === undefined) rows = walk(body.data, requestedPath); + +if (rows === undefined || rows === null) { + throw new Error('Nothing found at "' + requestedPath + '".' + candidates()); +} +if (!Array.isArray(rows)) { + rows = [rows]; +} + +const flatten = (value, prefix, out) => { + for (const key of Object.keys(value)) { + const child = value[key]; + const name = prefix ? prefix + '.' + key : key; + if (child !== null && typeof child === 'object' && !Array.isArray(child)) { + flatten(child, name, out); + } else { + out[name] = child; + } + } + return out; +}; + +result = rows.map((row) => + row !== null && typeof row === 'object' && !Array.isArray(row) + ? flatten(row, '', {}) + : { value: row } +); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/hyperdriveConfigs.js b/plugins/Cloudflare/v1/dataStreams/scripts/hyperdriveConfigs.js new file mode 100644 index 00000000..dbc9778e --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/hyperdriveConfigs.js @@ -0,0 +1,18 @@ +// Flattens the nested origin/caching objects and stamps the account id from the +// scoped object so the Hyperdrive analytics stream can build its query. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((cfg) => { + const origin = cfg.origin || {}; + const caching = cfg.caching || {}; + return { + sourceId: cfg.id, + configName: cfg.name || cfg.id, + accountId: accountId, + database: origin.database || "", + host: origin.host || "", + scheme: origin.scheme || "", + cachingDisabled: Boolean(caching.disabled), + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/kvNamespaces.js b/plugins/Cloudflare/v1/dataStreams/scripts/kvNamespaces.js new file mode 100644 index 00000000..9c97377d --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/kvNamespaces.js @@ -0,0 +1,11 @@ +// Stamps the account id from the scoped object onto every row so downstream +// KV analytics streams can build their account-scoped GraphQL query. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((ns) => ({ + sourceId: ns.id, + namespaceTitle: ns.title, + accountId: accountId, + supportsUrlEncoding: Boolean(ns.supports_url_encoding), +})); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/loadBalancerPoolHealth.js b/plugins/Cloudflare/v1/dataStreams/scripts/loadBalancerPoolHealth.js new file mode 100644 index 00000000..63390fa5 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/loadBalancerPoolHealth.js @@ -0,0 +1,28 @@ +// The pool health endpoint returns a doubly-nested map keyed by colo and then +// by origin name, which config cannot flatten - expandInnerObjects only reaches +// one level, and the keys are dynamic. Flatten to one row per origin per colo. +const popHealth = (data && data.result && data.result.pop_health) || {}; + +const rows = []; +for (const colo of Object.keys(popHealth)) { + const pop = popHealth[colo] || {}; + for (const entry of pop.origins || []) { + for (const originName of Object.keys(entry || {})) { + const o = entry[originName] || {}; + rows.push({ + colo: colo, + origin: originName, + healthy: Boolean(o.healthy), + responseCode: + typeof o.response_code === "number" + ? o.response_code + : null, + rtt: o.rtt || "", + failureReason: o.failure_reason || "", + coloHealthy: Boolean(pop.healthy), + }); + } + } +} + +result = rows; diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/loadBalancerPools.js b/plugins/Cloudflare/v1/dataStreams/scripts/loadBalancerPools.js new file mode 100644 index 00000000..c27b8aba --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/loadBalancerPools.js @@ -0,0 +1,21 @@ +// Collapses the nested origins array to a count and stamps the account id from +// the scoped object onto every row. +// Note: the list pools endpoint does not return a "healthy" field (Cloudflare's +// Pool schema has no such property here - health comes from the separate +// /pools/{id}/health endpoint, see the loadBalancerPoolHealth stream), so no +// healthy column is produced from this stream to avoid a misleading always-false value. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((pool) => ({ + sourceId: pool.id, + poolName: pool.name, + accountId: accountId, + enabled: Boolean(pool.enabled), + originCount: (pool.origins || []).length, + minimumOrigins: + typeof pool.minimum_origins === "number" ? pool.minimum_origins : null, + monitorId: pool.monitor || "", + createdOn: pool.created_on, + modifiedOn: pool.modified_on, +})); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/pagesDeployments.js b/plugins/Cloudflare/v1/dataStreams/scripts/pagesDeployments.js new file mode 100644 index 00000000..e826b3bc --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/pagesDeployments.js @@ -0,0 +1,19 @@ +// Flattens the deployment's nested latest_stage and deployment_trigger.metadata +// (two levels deep, beyond what expandInnerObjects can reach in one pass). +result = ((data && data.result) || []).map((deployment) => { + const stage = deployment.latest_stage || {}; + const trigger = deployment.deployment_trigger || {}; + const meta = trigger.metadata || {}; + + return { + short_id: deployment.short_id || deployment.id, + environment: deployment.environment || "", + status: stage.status || "", + stage: stage.name || "", + url: deployment.url || "", + branch: meta.branch || "", + commit: meta.commit_hash ? meta.commit_hash.substring(0, 7) : "", + commitMessage: meta.commit_message || "", + created_on: deployment.created_on, + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/pagesProjects.js b/plugins/Cloudflare/v1/dataStreams/scripts/pagesProjects.js new file mode 100644 index 00000000..c14ea26e --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/pagesProjects.js @@ -0,0 +1,23 @@ +// Flattens the deeply-nested latest_deployment.latest_stage structure and +// stamps the account id from the scoped object onto every row. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((project) => { + const latest = project.latest_deployment || {}; + const stage = latest.latest_stage || {}; + return { + sourceId: project.id, + projectName: project.name, + accountId: accountId, + subdomain: project.subdomain || "", + // Kept as an array, not a joined string: it is the join key for the + // Pages Project -> Zone correlation rule, and correlation matches an + // array property if any element matches. + domains: project.domains || [], + productionBranch: project.production_branch || "", + latestDeploymentStatus: stage.status || "", + latestDeploymentOn: latest.modified_on || latest.created_on, + createdOn: project.created_on, + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/queues.js b/plugins/Cloudflare/v1/dataStreams/scripts/queues.js new file mode 100644 index 00000000..4841e9c1 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/queues.js @@ -0,0 +1,27 @@ +// Collapses the producers/consumers arrays to counts and stamps the account id +// from the scoped object onto every row so the Queues analytics streams can +// build their account-scoped GraphQL query. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((queue) => ({ + sourceId: queue.queue_id, + queueName: queue.queue_name, + accountId: accountId, + producers: + typeof queue.producers_total_count === "number" + ? queue.producers_total_count + : (queue.producers || []).length, + consumers: + typeof queue.consumers_total_count === "number" + ? queue.consumers_total_count + : (queue.consumers || []).length, + // The consuming Worker script names, kept as an array: this is the join + // key for the Queue -> Worker correlation rule. HTTP-pull consumers have + // no service name and are filtered out. + consumerScripts: (queue.consumers || []) + .map((c) => c && c.service) + .filter(Boolean), + createdOn: queue.created_on, + modifiedOn: queue.modified_on, +})); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/r2Buckets.js b/plugins/Cloudflare/v1/dataStreams/scripts/r2Buckets.js new file mode 100644 index 00000000..fb5c59da --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/r2Buckets.js @@ -0,0 +1,14 @@ +// R2 nests the bucket array under result.buckets, and bucket names are only +// unique within an account, so the account id from the scoped object is +// prefixed onto the name to form a globally-unique sourceId. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result && data.result.buckets) || []).map((bucket) => ({ + sourceId: `${accountId}:${bucket.name}`, + bucketName: bucket.name, + accountId: accountId, + location: bucket.location || "", + storageClass: bucket.storage_class || "", + createdOn: bucket.creation_date, +})); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/rumPageLoads.js b/plugins/Cloudflare/v1/dataStreams/scripts/rumPageLoads.js new file mode 100644 index 00000000..eda82c73 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/rumPageLoads.js @@ -0,0 +1,28 @@ +// dataStreams/scripts/rumPageLoads.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the dimension value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.countryName vs dimensions.deviceType vs ...). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.accounts && + data.data.viewer.accounts[0] && + data.data.viewer.accounts[0].rumPageloadEventsAdaptiveGroups) || + []; + +result = groups.map((row) => { + const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; + const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); + + return { + date: row.dimensions && row.dimensions.date, + breakdown: label, + pageViews: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0, + visits: Number((row.sum && row.sum.visits) || 0) || 0 + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/tunnelConnections.js b/plugins/Cloudflare/v1/dataStreams/scripts/tunnelConnections.js new file mode 100644 index 00000000..e71561b0 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/tunnelConnections.js @@ -0,0 +1,15 @@ +// The connections endpoint returns one entry per connector, each with a nested +// `conns` array (the connector's individual edge connections). Flatten that +// array-into-rows structure so each row is one active connection, carrying the +// parent connector's architecture down onto every connection row. +result = ((data && data.result) || []).flatMap((connector) => + ((connector && connector.conns) || []).map((conn) => ({ + connectionId: conn.id, + colo_name: conn.colo_name, + origin_ip: conn.origin_ip, + opened_at: conn.opened_at, + client_version: conn.client_version || connector.version, + arch: connector.arch, + is_pending_reconnect: !!conn.is_pending_reconnect, + })), +); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/tunnels.js b/plugins/Cloudflare/v1/dataStreams/scripts/tunnels.js new file mode 100644 index 00000000..37c4be64 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/tunnels.js @@ -0,0 +1,14 @@ +// Collapses the nested connections array to a count and stamps the account id +// from the scoped object onto every row. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((tunnel) => ({ + sourceId: tunnel.id, + tunnelName: tunnel.name, + accountId: accountId, + status: tunnel.status || "", + tunnelType: tunnel.tun_type || "", + activeConnections: (tunnel.connections || []).length, + createdOn: tunnel.created_at, +})); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/vectorizeIndexes.js b/plugins/Cloudflare/v1/dataStreams/scripts/vectorizeIndexes.js new file mode 100644 index 00000000..c218ecc4 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/vectorizeIndexes.js @@ -0,0 +1,19 @@ +// Index names are only unique within an account, so the account id from the +// scoped object is prefixed onto the name to form a globally-unique sourceId. +// Also flattens the nested config object (dimensions/metric). +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((idx) => { + const cfg = idx.config || {}; + return { + sourceId: `${accountId}:${idx.name}`, + indexName: idx.name, + accountId: accountId, + dimensions: + typeof cfg.dimensions === "number" ? cfg.dimensions : null, + metric: cfg.metric || "", + createdOn: idx.created_on, + modifiedOn: idx.modified_on, + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/workerBindings.js b/plugins/Cloudflare/v1/dataStreams/scripts/workerBindings.js new file mode 100644 index 00000000..a2b96a31 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/workerBindings.js @@ -0,0 +1,44 @@ +// Emits ONE row per binding, as its own object type. +// +// It deliberately does NOT reuse the Worker's sourceId/type: when two import +// steps write the same object, the later step REPLACES the property set rather +// than merging it, so writing Worker objects here silently wiped every property +// the workerScripts step had set (accountId, usageModel, createdOn, ...). +// +// Each binding carries a type-specific SCALAR id column, populated only for its +// own type. Correlation rules then match one column per target type - a missing +// or empty value never matches, so the rules stay precise without relying on +// array-valued property matching. +const worker = (context.objects && context.objects[0]) || {}; +const rawId = worker.rawId || ""; +const accountId = rawId.indexOf(":") > -1 ? rawId.split(":")[0] : ""; +const scriptName = worker.name || ""; +const bindings = (data && data.result && data.result.bindings) || []; + +result = bindings + .filter((b) => b && b.type) + .map((b) => { + const bindingName = b.name || b.type; + const isD1 = b.type === "d1" || b.type === "d1_database"; + return { + sourceId: `${accountId}:${scriptName}:${bindingName}`, + bindingName: bindingName, + bindingType: b.type, + scriptName: scriptName, + accountId: accountId, + // Exactly one of these is populated per row, keyed by binding type. + kvNamespaceId: + b.type === "kv_namespace" ? b.namespace_id || "" : "", + r2BucketName: b.type === "r2_bucket" ? b.bucket_name || "" : "", + d1DatabaseId: isD1 ? b.id || b.database_id || "" : "", + queueName: b.type === "queue" ? b.queue_name || "" : "", + durableObjectNamespaceId: + b.type === "durable_object_namespace" + ? b.namespace_id || "" + : "", + vectorizeIndexName: + b.type === "vectorize" ? b.index_name || "" : "", + hyperdriveConfigId: b.type === "hyperdrive" ? b.id || "" : "", + serviceName: b.type === "service" ? b.service || "" : "", + }; + }); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/workerRoutes.js b/plugins/Cloudflare/v1/dataStreams/scripts/workerRoutes.js new file mode 100644 index 00000000..ead189e9 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/workerRoutes.js @@ -0,0 +1,18 @@ +// Routes are the join object between a Worker and the Zone it serves, so this +// stamps both sides' keys onto each row: zoneId from the scoped Zone object and +// scriptName from the route itself. A correlation Bridge rule then relates +// Worker -> Worker Route -> Zone. Routes with no script attached are dropped - +// they cannot participate in that relationship. +const zone = (context.objects && context.objects[0]) || {}; +const zoneId = zone.rawId || ""; +const zoneName = zone.name || ""; + +result = ((data && data.result) || []) + .filter((route) => route && route.script) + .map((route) => ({ + sourceId: route.id, + pattern: route.pattern, + zoneId: zoneId, + zoneName: zoneName, + scriptName: route.script, + })); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/workerScripts.js b/plugins/Cloudflare/v1/dataStreams/scripts/workerScripts.js new file mode 100644 index 00000000..02a2c78c --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/workerScripts.js @@ -0,0 +1,17 @@ +// Build a globally-unique sourceId for each Worker script. +// Script names are only unique within an account, so the account id from the +// scoped object is prefixed onto the name. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((script) => ({ + sourceId: `${accountId}:${script.id}`, + scriptName: script.id, + accountId: accountId, + usageModel: script.usage_model || "", + handlers: (script.handlers || []).join(", "), + placementMode: (script.placement && script.placement.mode) || "", + logpush: Boolean(script.logpush), + createdOn: script.created_on, + modifiedOn: script.modified_on, +})); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/workersAiInference.js b/plugins/Cloudflare/v1/dataStreams/scripts/workersAiInference.js new file mode 100644 index 00000000..2a0f213c --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/workersAiInference.js @@ -0,0 +1,33 @@ +// dataStreams/scripts/workersAiInference.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the breakdown value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.modelId vs dimensions.requestSource vs dimensions.errorCode). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen, and +// derive an average inference time per request (the API only returns a per-group total). + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.accounts && + data.data.viewer.accounts[0] && + data.data.viewer.accounts[0].aiInferenceAdaptiveGroups) || + []; + +result = groups.map((row) => { + const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; + const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); + const requests = Number((row.count !== undefined && row.count !== null ? row.count : 0)) || 0; + const totalDurationMs = Number((row.sum && row.sum.totalInferenceTimeMs) || 0) || 0; + + return { + date: row.dimensions && row.dimensions.date, + breakdown: label, + requests: requests, + inputTokens: Number((row.sum && row.sum.totalInputTokens) || 0) || 0, + outputTokens: Number((row.sum && row.sum.totalOutputTokens) || 0) || 0, + avgDurationMs: requests > 0 ? Math.round((totalDurationMs / requests) * 100) / 100 : 0 + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/zoneCertificates.js b/plugins/Cloudflare/v1/dataStreams/scripts/zoneCertificates.js new file mode 100644 index 00000000..1f63e602 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/zoneCertificates.js @@ -0,0 +1,15 @@ +// Flattens each certificate pack's nested certificates[] array into one row +// per certificate, since the expiry date lives on the inner certificate, not +// the pack. +result = ((data && data.result) || []).flatMap((pack) => + (pack.certificates || []).map((cert) => ({ + id: cert.id, + hosts: (cert.hosts || pack.hosts || []).join(", "), + status: cert.status, + certificateAuthority: pack.certificate_authority, + type: pack.type, + validationMethod: pack.validation_method, + expiresOn: cert.expires_on, + issuer: cert.issuer, + })), +); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/zoneDnsAnalytics.js b/plugins/Cloudflare/v1/dataStreams/scripts/zoneDnsAnalytics.js new file mode 100644 index 00000000..0a08a103 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/zoneDnsAnalytics.js @@ -0,0 +1,28 @@ +// dataStreams/scripts/zoneDnsAnalytics.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the dimension value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.queryName vs dimensions.queryType vs ...). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.zones && + data.data.viewer.zones[0] && + data.data.viewer.zones[0].dnsAnalyticsAdaptiveGroups) || + []; + +result = groups.map((row) => { + const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; + const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); + + return { + date: row.dimensions && row.dimensions.date, + breakdown: label, + queryCount: Number((row.count !== undefined && row.count !== null ? row.count : 0)) || 0, + avgResponseTimeMs: Number((row.avg && row.avg.processingTimeUs) || 0) / 1000 + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/zoneFirewallEvents.js b/plugins/Cloudflare/v1/dataStreams/scripts/zoneFirewallEvents.js new file mode 100644 index 00000000..94246d9b --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/zoneFirewallEvents.js @@ -0,0 +1,31 @@ +// dataStreams/scripts/zoneFirewallEvents.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the selected dimension's value inside each row's `dimensions` object varies +// with the user-selected breakdown (dimensions.ruleId vs dimensions.source vs ...). The +// `action` dimension is always present under a fixed key. Normalise both to stable +// columns regardless of which breakdown dimension was chosen. + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.zones && + data.data.viewer.zones[0] && + data.data.viewer.zones[0].firewallEventsAdaptiveGroups) || + []; + +result = groups.map((row) => { + const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; + const breakdown = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); + + const rawAction = row.dimensions && row.dimensions.action; + const action = rawAction === undefined || rawAction === null || rawAction === "" ? "Unknown" : String(rawAction); + + return { + breakdown: breakdown, + action: action, + events: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0 + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/zoneTrafficBreakdown.js b/plugins/Cloudflare/v1/dataStreams/scripts/zoneTrafficBreakdown.js new file mode 100644 index 00000000..c1868df5 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/zoneTrafficBreakdown.js @@ -0,0 +1,28 @@ +// dataStreams/scripts/zoneTrafficBreakdown.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the dimension value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.clientCountryName vs dimensions.cacheStatus vs ...). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.zones && + data.data.viewer.zones[0] && + data.data.viewer.zones[0].httpRequestsAdaptiveGroups) || + []; + +result = groups.map((row) => { + const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; + const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); + + return { + breakdown: label, + requests: Number((row.count !== undefined && row.count !== null ? row.count : 0)) || 0, + bytes: Number((row.sum && row.sum.edgeResponseBytes) || 0) || 0, + visits: Number((row.sum && row.sum.visits) || 0) || 0 + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/tunnelConnections.json b/plugins/Cloudflare/v1/dataStreams/tunnelConnections.json new file mode 100644 index 00000000..854e8d45 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/tunnelConnections.json @@ -0,0 +1,61 @@ +{ + "name": "tunnelConnections", + "displayName": "Tunnel Connections", + "description": "Active connector connections for a Cloudflare Tunnel", + "tags": ["Network"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.accountId}}/cfd_tunnel/{{object.rawId}}/connections", + "postRequestScript": "tunnelConnections.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Tunnel"] } + }, + "metadata": [ + { + "name": "connectionId", + "displayName": "Connection ID", + "shape": "string", + "visible": false + }, + { + "name": "colo_name", + "displayName": "Colo", + "shape": "string", + "role": "label" + }, + { + "name": "origin_ip", + "displayName": "Origin IP", + "shape": "string" + }, + { + "name": "opened_at", + "displayName": "Opened", + "shape": "date", + "role": "timestamp" + }, + { + "name": "client_version", + "displayName": "Connector Version", + "shape": "string" + }, + { + "name": "arch", + "displayName": "Architecture", + "shape": "string" + }, + { + "name": "is_pending_reconnect", + "displayName": "Pending Reconnect", + "shape": "boolean" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/tunnels.json b/plugins/Cloudflare/v1/dataStreams/tunnels.json new file mode 100644 index 00000000..83c0753c --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/tunnels.json @@ -0,0 +1,136 @@ +{ + "name": "tunnels", + "displayName": "Tunnels", + "description": "Cloudflare Tunnels in an account with their connection status", + "tags": [ + "Network" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/cfd_tunnel", + "getArgs": [ + { + "key": "is_deleted", + "value": "false" + } + ], + "postRequestScript": "tunnels.js", + "paging": { + "mode": "offset", + "pageSize": { + "realm": "queryArg", + "path": "per_page", + "value": "100" + }, + "offset": { + "mode": "page", + "rowCountIn": { + "realm": "payloadArraySize", + "path": "result" + }, + "base": 1 + }, + "out": { + "realm": "queryArg", + "path": "page" + } + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "tunnelName", + "displayName": "Tunnel", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare Tunnel" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "status", + "displayName": "Status", + "shape": [ + "state", + { + "map": { + "success": [ + "healthy" + ], + "warning": [ + "degraded", + "inactive" + ], + "error": [ + "down" + ] + } + } + ] + }, + { + "name": "tunnelType", + "displayName": "Type", + "shape": "string" + }, + { + "name": "activeConnections", + "displayName": "Active Connections", + "shape": "number" + }, + { + "name": "createdOn", + "displayName": "Created", + "shape": "date" + }, + { + "name": "healthState", + "displayName": "Health", + "computed": true, + "valueExpression": "{{ $['status'] === 'healthy' ? 'success' : ((($['status'] === 'degraded') || ($['status'] === 'inactive')) ? 'warning' : 'error') }}", + "shape": [ + "state", + { + "map": { + "success": [ + "success" + ], + "warning": [ + "warning" + ], + "error": [ + "error" + ] + } + } + ] + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/vectorizeIndexes.json b/plugins/Cloudflare/v1/dataStreams/vectorizeIndexes.json new file mode 100644 index 00000000..95e349c4 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/vectorizeIndexes.json @@ -0,0 +1,48 @@ +{ + "name": "vectorizeIndexes", + "displayName": "Vectorize Indexes", + "description": "Vectorize vector database indexes in a Cloudflare account", + "tags": ["Database", "Storage"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/vectorize/v2/indexes", + "postRequestScript": "vectorizeIndexes.js", + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Account"] } + }, + "visibility": { "type": "hidden" }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "indexName", + "displayName": "Index", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare Vectorize Index" + }, + { "name": "accountId", "displayName": "Account ID", "shape": "string" }, + { + "name": "dimensions", + "displayName": "Dimensions", + "shape": "number" + }, + { "name": "metric", "displayName": "Metric", "shape": "string" }, + { "name": "createdOn", "displayName": "Created", "shape": "date" }, + { "name": "modifiedOn", "displayName": "Modified", "shape": "date" } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/vectorizeQueries.json b/plugins/Cloudflare/v1/dataStreams/vectorizeQueries.json new file mode 100644 index 00000000..d6a2748d --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/vectorizeQueries.json @@ -0,0 +1,54 @@ +{ + "name": "vectorizeQueries", + "displayName": "Vectorize Queries", + "description": "Daily query count and query latency for a Vectorize index", + "tags": ["Database", "Analytics"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$indexName:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){vectorizeV2QueriesAdaptiveGroups(limit:10000,filter:{indexName:$indexName,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){count avg{requestDurationMs} dimensions{date}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "indexName": "{{object.name}}", + "start": "{{timeframe.start.split('T')[0]}}", + "end": "{{timeframe.end.split('T')[0]}}" + } + }, + "pathToData": "data.viewer.accounts.0.vectorizeV2QueriesAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare Vectorize Index"] + } + }, + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "count", + "displayName": "Queries", + "shape": "number", + "role": "value" + }, + { + "name": "avg.requestDurationMs", + "displayName": "Avg Query Latency", + "shape": "milliseconds" + } + ], + "timeframes": ["last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/vectorizeStorage.json b/plugins/Cloudflare/v1/dataStreams/vectorizeStorage.json new file mode 100644 index 00000000..bea67517 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/vectorizeStorage.json @@ -0,0 +1,54 @@ +{ + "name": "vectorizeStorage", + "displayName": "Vectorize Storage", + "description": "Daily stored vector count and dimensionality for a Vectorize index", + "tags": ["Database", "Storage"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$indexName:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){vectorizeV2StorageAdaptiveGroups(limit:10000,filter:{indexName:$indexName,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){max{storedVectorDimensions vectorCount} dimensions{date}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "indexName": "{{object.name}}", + "start": "{{timeframe.start.split('T')[0]}}", + "end": "{{timeframe.end.split('T')[0]}}" + } + }, + "pathToData": "data.viewer.accounts.0.vectorizeV2StorageAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare Vectorize Index"] + } + }, + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "max.vectorCount", + "displayName": "Stored Vectors", + "shape": "number", + "role": "value" + }, + { + "name": "max.storedVectorDimensions", + "displayName": "Stored Vector Dimensions", + "shape": "number" + } + ], + "timeframes": ["last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/verifyToken.json b/plugins/Cloudflare/v1/dataStreams/verifyToken.json new file mode 100644 index 00000000..9c7528bc --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/verifyToken.json @@ -0,0 +1,39 @@ +{ + "name": "verifyToken", + "displayName": "Token Status", + "description": "Status and expiry of the API token the plugin authenticates with", + "tags": ["Security"], + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "user/tokens/verify", + "pathToData": "result", + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": "none", + "visibility": { "type": "hidden" }, + "metadata": [ + { "name": "id", "displayName": "Token ID", "shape": "string" }, + { + "name": "status", + "displayName": "Status", + "shape": ["state", { "map": { "success": ["active"] } }] + }, + { + "name": "not_before", + "displayName": "Valid From", + "shape": "date" + }, + { + "name": "expires_on", + "displayName": "Expires On", + "shape": "date" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/workerBindings.json b/plugins/Cloudflare/v1/dataStreams/workerBindings.json new file mode 100644 index 00000000..dcf3f3fa --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/workerBindings.json @@ -0,0 +1,54 @@ +{ + "name": "workerBindings", + "displayName": "Worker Bindings", + "description": "Resources bound to a Worker script, such as KV namespaces, R2 buckets, D1 databases and queues", + "tags": ["Workers"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.accountId}}/workers/scripts/{{object.name}}/settings", + "postRequestScript": "workerBindings.js", + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Worker"] } + }, + "visibility": { "type": "hidden" }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "bindingName", + "displayName": "Binding", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare Worker Binding" + }, + { "name": "bindingType", "displayName": "Type", "shape": "string" }, + { "name": "scriptName", "displayName": "Worker", "shape": "string" }, + { "name": "accountId", "displayName": "Account ID", "shape": "string" }, + { "name": "kvNamespaceId", "visible": false, "shape": "string" }, + { "name": "r2BucketName", "visible": false, "shape": "string" }, + { "name": "d1DatabaseId", "visible": false, "shape": "string" }, + { "name": "queueName", "visible": false, "shape": "string" }, + { + "name": "durableObjectNamespaceId", + "visible": false, + "shape": "string" + }, + { "name": "vectorizeIndexName", "visible": false, "shape": "string" }, + { "name": "hyperdriveConfigId", "visible": false, "shape": "string" }, + { "name": "serviceName", "visible": false, "shape": "string" } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/workerInvocations.json b/plugins/Cloudflare/v1/dataStreams/workerInvocations.json new file mode 100644 index 00000000..16a6173f --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/workerInvocations.json @@ -0,0 +1,106 @@ +{ + "name": "workerInvocations", + "displayName": "Worker Invocations", + "description": "Request, error and CPU time metrics for a Worker script", + "tags": [ + "Workers", + "Analytics" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$scriptName:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){workersInvocationsAdaptive(limit:10000,filter:{scriptName:$scriptName,datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){sum{requests errors subrequests}quantiles{cpuTimeP50 cpuTimeP99}dimensions{datetime status scriptName}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "scriptName": "{{object.name}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "pathToData": "data.viewer.accounts.0.workersInvocationsAdaptive", + "expandInnerObjects": true, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Worker" + ] + } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "sum.requests", + "displayName": "Requests", + "shape": "number", + "role": "value" + }, + { + "name": "sum.errors", + "displayName": "Errors", + "shape": "number" + }, + { + "name": "sum.subrequests", + "displayName": "Subrequests", + "shape": "number" + }, + { + "name": "quantiles.cpuTimeP50", + "displayName": "CPU Time P50 (raw)", + "shape": "number", + "visible": false + }, + { + "name": "cpuTimeP50Ms", + "displayName": "CPU Time P50", + "computed": true, + "valueExpression": "{{ Number($['quantiles.cpuTimeP50']) / 1000 }}", + "shape": ["milliseconds", { "decimalPlaces": 2 }] + }, + { + "name": "quantiles.cpuTimeP99", + "displayName": "CPU Time P99 (raw)", + "shape": "number", + "visible": false + }, + { + "name": "cpuTimeP99Ms", + "displayName": "CPU Time P99", + "computed": true, + "valueExpression": "{{ Number($['quantiles.cpuTimeP99']) / 1000 }}", + "shape": ["milliseconds", { "decimalPlaces": 2 }] + }, + { + "name": "dimensions.status", + "displayName": "Status", + "shape": "string" + }, + { + "name": "errorRate", + "displayName": "Error Rate", + "computed": true, + "valueExpression": "{{ Number($['sum.requests']) > 0 ? Math.round(10000 * Number($['sum.errors']) / Number($['sum.requests'])) / 100 : 0 }}", + "shape": ["percent", { "decimalPlaces": 2 }] + } + ], + "timeframes": [ + "last12hours", + "last24hours", + "last7days", + "last30days" + ] +} \ No newline at end of file diff --git a/plugins/Cloudflare/v1/dataStreams/workerRoutes.json b/plugins/Cloudflare/v1/dataStreams/workerRoutes.json new file mode 100644 index 00000000..f6fb05d7 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/workerRoutes.json @@ -0,0 +1,46 @@ +{ + "name": "workerRoutes", + "displayName": "Worker Routes", + "description": "URL patterns that route requests on a zone to a Worker script", + "tags": ["Workers", "Zone"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "zones/{{object.rawId}}/workers/routes", + "postRequestScript": "workerRoutes.js", + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "visibility": { "type": "hidden" }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "pattern", + "displayName": "Route", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare Worker Route" + }, + { "name": "zoneId", "displayName": "Zone ID", "shape": "string" }, + { "name": "zoneName", "displayName": "Zone", "shape": "string" }, + { + "name": "scriptName", + "displayName": "Worker", + "shape": "string" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/workerScripts.json b/plugins/Cloudflare/v1/dataStreams/workerScripts.json new file mode 100644 index 00000000..32eeb657 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/workerScripts.json @@ -0,0 +1,85 @@ +{ + "name": "workerScripts", + "displayName": "Worker Scripts", + "description": "Worker scripts deployed in a Cloudflare account", + "tags": [ + "Workers" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/workers/scripts", + "postRequestScript": "workerScripts.js", + "paging": { + "mode": "none" + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "scriptName", + "displayName": "Worker", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare Worker" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "usageModel", + "displayName": "Usage Model", + "shape": "string" + }, + { + "name": "handlers", + "displayName": "Handlers", + "shape": "string" + }, + { + "name": "placementMode", + "displayName": "Placement Mode", + "shape": "string" + }, + { + "name": "logpush", + "displayName": "Logpush", + "shape": "boolean" + }, + { + "name": "createdOn", + "displayName": "Created", + "shape": "date" + }, + { + "name": "modifiedOn", + "displayName": "Modified", + "shape": "date" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/workersAiInference.json b/plugins/Cloudflare/v1/dataStreams/workersAiInference.json new file mode 100644 index 00000000..209b68fc --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/workersAiInference.json @@ -0,0 +1,78 @@ +{ + "name": "workersAiInference", + "displayName": "Workers AI Inference", + "description": "Inference request counts, token usage and latency for Workers AI grouped by a selectable dimension", + "tags": ["Workers", "Analytics"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiInferenceAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count sum{totalInputTokens totalOutputTokens totalInferenceTimeMs}dimensions{date {{breakdown}}}}}}}", + "variables": { + "accountTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "workersAiInference.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Account"] } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "modelId", + "options": [ + { "value": "modelId", "label": "Model" }, + { "value": "requestSource", "label": "Request Source" }, + { "value": "errorCode", "label": "Error Code" } + ] + } + ], + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "requests", + "displayName": "Requests", + "shape": "number", + "role": "value" + }, + { + "name": "inputTokens", + "displayName": "Input Tokens", + "shape": "number" + }, + { + "name": "outputTokens", + "displayName": "Output Tokens", + "shape": "number" + }, + { + "name": "avgDurationMs", + "displayName": "Avg Inference Time", + "shape": ["milliseconds", { "decimalPlaces": 2 }] + } + ], + "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/zoneCertificates.json b/plugins/Cloudflare/v1/dataStreams/zoneCertificates.json new file mode 100644 index 00000000..726cf382 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/zoneCertificates.json @@ -0,0 +1,91 @@ +{ + "name": "zoneCertificates", + "displayName": "SSL Certificates", + "description": "SSL certificate packs for a Cloudflare zone with issuer, validation method and expiry details", + "tags": ["Zone", "Security"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "zones/{{object.rawId}}/ssl/certificate_packs", + "postRequestScript": "zoneCertificates.js", + "paging": { + "mode": "offset", + "pageSize": { + "realm": "queryArg", + "path": "per_page", + "value": "50" + }, + "offset": { + "mode": "page", + "rowCountIn": { "realm": "payloadArraySize", "path": "result" }, + "base": 1 + }, + "out": { "realm": "queryArg", "path": "page" } + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "metadata": [ + { "name": "hosts", "displayName": "Hosts", "shape": "string" }, + { + "name": "status", + "displayName": "Status", + "shape": [ + "state", + { + "map": { + "success": ["active", "deployed"], + "warning": [ + "pending_validation", + "pending_issuance", + "pending_deployment", + "pending_expiration", + "pending_deletion", + "initializing", + "deleting" + ], + "error": ["expired", "deleted"] + } + } + ] + }, + { + "name": "certificateAuthority", + "displayName": "Authority", + "shape": "string" + }, + { "name": "type", "displayName": "Type", "shape": "string" }, + { + "name": "validationMethod", + "displayName": "Validation Method", + "shape": "string" + }, + { + "name": "expiresOn", + "displayName": "Expires", + "shape": "date", + "role": "value" + }, + { + "name": "daysUntilExpiry", + "displayName": "Days Until Expiry", + "computed": true, + "valueExpression": "{{ Math.round((new Date($['expiresOn']) - new Date()) / 86400000) }}", + "shape": "number" + }, + { "name": "issuer", "displayName": "Issuer", "shape": "string" }, + { + "name": "id", + "displayName": "Certificate ID", + "shape": "string", + "visible": false + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/zoneDnsAnalytics.json b/plugins/Cloudflare/v1/dataStreams/zoneDnsAnalytics.json new file mode 100644 index 00000000..5122ab86 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/zoneDnsAnalytics.json @@ -0,0 +1,69 @@ +{ + "name": "zoneDnsAnalytics", + "displayName": "DNS Analytics", + "description": "DNS query counts and response times for a zone grouped by a selectable dimension", + "tags": ["Zone", "DNS"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){dnsAnalyticsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count avg{processingTimeUs} dimensions{date {{breakdown}}}}}}}", + "variables": { + "zoneTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "zoneDnsAnalytics.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "queryName", + "options": [ + { "value": "queryName", "label": "Query Name" }, + { "value": "queryType", "label": "Query Type" }, + { "value": "responseCode", "label": "Response Code" }, + { "value": "coloName", "label": "Edge Location" } + ] + } + ], + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "queryCount", + "displayName": "Query Count", + "shape": "number", + "role": "value" + }, + { + "name": "avgResponseTimeMs", + "displayName": "Avg Response Time", + "shape": "milliseconds" + } + ], + "timeframes": ["last12hours", "last24hours", "last7days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/zoneDnsRecords.json b/plugins/Cloudflare/v1/dataStreams/zoneDnsRecords.json new file mode 100644 index 00000000..38ca9ce5 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/zoneDnsRecords.json @@ -0,0 +1,64 @@ +{ + "name": "zoneDnsRecords", + "displayName": "DNS Records", + "description": "DNS records configured on a Cloudflare zone", + "tags": ["Zone", "DNS"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "zones/{{object.rawId}}/dns_records", + "pathToData": "result", + "paging": { + "mode": "offset", + "pageSize": { "realm": "queryArg", "path": "per_page", "value": "100" }, + "offset": { + "mode": "page", + "rowCountIn": { "realm": "payloadArraySize", "path": "result" }, + "base": 1 + }, + "out": { "realm": "queryArg", "path": "page" } + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "metadata": [ + { + "name": "id", + "displayName": "Record ID", + "shape": "string", + "role": "id", + "visible": false + }, + { + "name": "name", + "displayName": "Name", + "shape": "string", + "role": "label" + }, + { "name": "type", "displayName": "Type", "shape": "string" }, + { "name": "content", "displayName": "Content", "shape": "string" }, + { + "name": "ttl", + "displayName": "TTL", + "shape": "seconds", + "formatExpression": "{{ $['ttl'] === 1 ? 'Auto' : $['ttl'] }}" + }, + { "name": "proxied", "displayName": "Proxied", "shape": "boolean" }, + { "name": "comment", "displayName": "Comment", "shape": "string" }, + { + "name": "tags", + "displayName": "Tags", + "valueExpression": "{{ Array.isArray($['tags']) ? $['tags'].join(', ') : ($['tags'] || '') }}", + "shape": "string" + }, + { "name": "created_on", "displayName": "Created", "shape": "date" }, + { "name": "modified_on", "displayName": "Modified", "shape": "date" } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/zoneFirewallEvents.json b/plugins/Cloudflare/v1/dataStreams/zoneFirewallEvents.json new file mode 100644 index 00000000..3b2151c5 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/zoneFirewallEvents.json @@ -0,0 +1,81 @@ +{ + "name": "zoneFirewallEvents", + "displayName": "Zone Firewall Events", + "description": "Firewall event counts for a zone grouped by action and a selectable dimension", + "tags": ["Zone", "Security"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){firewallEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{action {{breakdown}} }}}}}", + "variables": { + "zoneTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "zoneFirewallEvents.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "source", + "options": [ + { "value": "ruleId", "label": "Rule" }, + { "value": "source", "label": "Service" }, + { "value": "clientCountryName", "label": "Country" }, + { "value": "clientRequestHTTPHost", "label": "Host" }, + { "value": "userAgent", "label": "User Agent" }, + { "value": "clientRequestPath", "label": "Path" } + ] + } + ], + "metadata": [ + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "action", + "displayName": "Action", + "shape": "string" + }, + { + "name": "actionState", + "displayName": "Severity", + "computed": true, + "valueExpression": "{{ $['action'] }}", + "shape": [ + "state", + { + "map": { + "error": ["block", "drop"], + "warning": ["challenge", "managed_challenge", "jschallenge"], + "success": ["allow", "skip", "log"] + } + } + ] + }, + { + "name": "events", + "displayName": "Events", + "shape": "number", + "role": "value" + } + ], + "timeframes": ["last12hours", "last24hours"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/zoneHealthChecks.json b/plugins/Cloudflare/v1/dataStreams/zoneHealthChecks.json new file mode 100644 index 00000000..f69012cf --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/zoneHealthChecks.json @@ -0,0 +1,87 @@ +{ + "name": "zoneHealthChecks", + "displayName": "Health Checks", + "description": "Standalone health check results for a zone", + "tags": ["Zone", "Availability"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "zones/{{object.rawId}}/healthchecks", + "pathToData": "result", + "paging": { + "mode": "offset", + "pageSize": { "realm": "queryArg", "path": "per_page", "value": "50" }, + "offset": { + "mode": "page", + "rowCountIn": { "realm": "payloadArraySize", "path": "result" }, + "base": 1 + }, + "out": { "realm": "queryArg", "path": "page" } + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "metadata": [ + { + "name": "name", + "displayName": "Name", + "shape": "string", + "role": "label" + }, + { "name": "address", "displayName": "Address", "shape": "string" }, + { "name": "type", "displayName": "Type", "shape": "string" }, + { + "name": "status", + "displayName": "Status", + "shape": [ + "state", + { + "map": { + "success": ["healthy"], + "error": ["unhealthy"], + "warning": ["suspended", "unknown"] + } + } + ] + }, + { + "name": "failure_reason", + "displayName": "Failure Reason", + "shape": "string" + }, + { "name": "suspended", "displayName": "Suspended", "shape": "boolean" }, + { "name": "interval", "displayName": "Interval", "shape": "seconds" }, + { "name": "timeout", "displayName": "Timeout", "shape": "seconds" }, + { + "name": "consecutive_fails", + "displayName": "Consecutive Fails", + "shape": "number" + }, + { + "name": "consecutive_successes", + "displayName": "Consecutive Successes", + "shape": "number" + }, + { + "name": "check_regions", + "displayName": "Regions", + "valueExpression": "{{ Array.isArray($['check_regions']) ? $['check_regions'].join(', ') : ($['check_regions'] || '') }}", + "shape": "string" + }, + { + "name": "id", + "displayName": "Health Check ID", + "shape": "string", + "visible": false + }, + { "name": "created_on", "displayName": "Created", "shape": "date" }, + { "name": "modified_on", "displayName": "Modified", "shape": "date" } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/zoneLoadBalancing.json b/plugins/Cloudflare/v1/dataStreams/zoneLoadBalancing.json new file mode 100644 index 00000000..27919ee9 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/zoneLoadBalancing.json @@ -0,0 +1,59 @@ +{ + "name": "zoneLoadBalancing", + "displayName": "Load Balancing Requests", + "description": "Load balancer request counts for a zone broken down by load balancer, selected pool, origin and colo", + "tags": ["Zone", "Network"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){loadBalancingRequestsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{lbName selectedPoolName selectedOriginName coloCode}}}}}", + "variables": { + "zoneTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "pathToData": "data.viewer.zones.0.loadBalancingRequestsAdaptiveGroups", + "expandInnerObjects": true, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "metadata": [ + { + "name": "dimensions.lbName", + "displayName": "Load Balancer", + "shape": "string", + "role": "label" + }, + { + "name": "dimensions.selectedPoolName", + "displayName": "Pool", + "shape": "string" + }, + { + "name": "dimensions.selectedOriginName", + "displayName": "Origin", + "shape": "string" + }, + { + "name": "dimensions.coloCode", + "displayName": "Colo", + "shape": "string" + }, + { + "name": "count", + "displayName": "Requests", + "shape": "number", + "role": "value" + } + ], + "timeframes": ["last12hours", "last24hours"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/zoneTraffic.json b/plugins/Cloudflare/v1/dataStreams/zoneTraffic.json new file mode 100644 index 00000000..79c35676 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/zoneTraffic.json @@ -0,0 +1,97 @@ +{ + "name": "zoneTraffic", + "displayName": "Zone Traffic", + "description": "Hourly HTTP request, cache and bandwidth totals for a zone", + "tags": [ + "Zone", + "Analytics" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){httpRequests1hGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){dimensions{datetime}sum{requests cachedRequests bytes cachedBytes threats pageViews encryptedRequests}uniq{uniques}}}}}", + "variables": { + "zoneTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "pathToData": "data.viewer.zones.0.httpRequests1hGroups", + "expandInnerObjects": true, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Zone" + ] + } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "sum.requests", + "displayName": "Requests", + "shape": "number", + "role": "value" + }, + { + "name": "sum.cachedRequests", + "displayName": "Cached Requests", + "shape": "number" + }, + { + "name": "sum.bytes", + "displayName": "Bytes", + "shape": "bytes" + }, + { + "name": "sum.cachedBytes", + "displayName": "Cached Bytes", + "shape": "bytes" + }, + { + "name": "sum.threats", + "displayName": "Threats", + "shape": "number" + }, + { + "name": "sum.pageViews", + "displayName": "Page Views", + "shape": "number" + }, + { + "name": "sum.encryptedRequests", + "displayName": "Encrypted Requests", + "shape": "number" + }, + { + "name": "uniq.uniques", + "displayName": "Unique Visitors", + "shape": "number" + }, + { + "name": "cacheHitRatio", + "displayName": "Cache Hit Ratio", + "computed": true, + "valueExpression": "{{ Number($['sum.requests']) > 0 ? Math.round(10000 * Number($['sum.cachedRequests']) / Number($['sum.requests'])) / 100 : 0 }}", + "shape": ["percent", { "decimalPlaces": 2 }] + } + ], + "timeframes": [ + "last12hours", + "last24hours" + ] +} \ No newline at end of file diff --git a/plugins/Cloudflare/v1/dataStreams/zoneTrafficBreakdown.json b/plugins/Cloudflare/v1/dataStreams/zoneTrafficBreakdown.json new file mode 100644 index 00000000..ec1c4176 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/zoneTrafficBreakdown.json @@ -0,0 +1,71 @@ +{ + "name": "zoneTrafficBreakdown", + "displayName": "Zone Traffic Breakdown", + "description": "HTTP request counts, bytes and visits for a zone grouped by a selectable dimension", + "tags": ["Zone", "Analytics"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){httpRequestsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count sum{edgeResponseBytes visits} dimensions{ {{breakdown}} }}}}}", + "variables": { + "zoneTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "zoneTrafficBreakdown.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "clientCountryName", + "options": [ + { "value": "clientCountryName", "label": "Country" }, + { "value": "edgeResponseStatus", "label": "Status Code" }, + { "value": "cacheStatus", "label": "Cache Status" }, + { "value": "clientRequestHTTPHost", "label": "Host" }, + { "value": "clientDeviceType", "label": "Device Type" }, + { "value": "clientRequestHTTPProtocol", "label": "HTTP Protocol" }, + { "value": "edgeResponseContentTypeName", "label": "Content Type" } + ] + } + ], + "metadata": [ + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "requests", + "displayName": "Requests", + "shape": "number", + "role": "value" + }, + { + "name": "bytes", + "displayName": "Bytes", + "shape": "bytes" + }, + { + "name": "visits", + "displayName": "Visits", + "shape": "number" + } + ], + "timeframes": ["last12hours", "last24hours", "last7days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/zones.json b/plugins/Cloudflare/v1/dataStreams/zones.json new file mode 100644 index 00000000..3cdf75c9 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/zones.json @@ -0,0 +1,180 @@ +{ + "name": "zones", + "displayName": "Zones", + "description": "Cloudflare zones with their status, plan and owning account", + "tags": [ + "Zone" + ], + "baseDataSourceName": "httpRequestUnscoped", + "config": { + "httpMethod": "get", + "endpointPath": "zones", + "pathToData": "result", + "expandInnerObjects": true, + "paging": { + "mode": "offset", + "pageSize": { + "realm": "queryArg", + "path": "per_page", + "value": "50" + }, + "offset": { + "mode": "page", + "rowCountIn": { + "realm": "payloadArraySize", + "path": "result" + }, + "base": 1 + }, + "out": { + "realm": "queryArg", + "path": "page" + } + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": "none", + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "id", + "displayName": "Zone ID", + "shape": "string", + "role": "id" + }, + { + "name": "name", + "displayName": "Zone", + "shape": "string", + "role": "label", + "sourceId": "id", + "sourceType": "Cloudflare Zone" + }, + { + "name": "status", + "displayName": "Status", + "shape": [ + "state", + { + "map": { + "success": [ + "active" + ], + "warning": [ + "pending", + "initializing", + "read only" + ], + "error": [ + "moved", + "deactivated", + "deleted" + ] + } + } + ] + }, + { + "name": "paused", + "displayName": "Paused", + "shape": "boolean" + }, + { + "name": "type", + "displayName": "Zone Type", + "shape": "string" + }, + { + "name": "development_mode", + "visible": false, + "shape": "number" + }, + { + "name": "developmentModeActive", + "displayName": "Development Mode", + "computed": true, + "valueExpression": "{{ Number($['development_mode']) > 0 }}", + "shape": "boolean" + }, + { + "name": "account.id", + "visible": false, + "shape": "string" + }, + { + "name": "account.name", + "visible": false, + "shape": "string" + }, + { + "name": "plan.name", + "visible": false, + "shape": "string" + }, + { + "name": "accountId", + "displayName": "Account ID", + "computed": true, + "valueExpression": "{{ $['account.id'] }}", + "shape": "string" + }, + { + "name": "accountName", + "displayName": "Account", + "computed": true, + "valueExpression": "{{ $['account.name'] }}", + "shape": "string" + }, + { + "name": "planName", + "displayName": "Plan", + "computed": true, + "valueExpression": "{{ $['plan.name'] }}", + "shape": "string" + }, + { + "name": "created_on", + "displayName": "Created", + "shape": "date" + }, + { + "name": "activated_on", + "displayName": "Activated", + "shape": "date" + }, + { + "name": "name_servers", + "displayName": "Name Servers", + "shape": "string" + }, + { + "name": "healthState", + "displayName": "Health", + "computed": true, + "valueExpression": "{{ $['status'] === 'active' ? 'success' : ((($['status'] === 'pending') || ($['status'] === 'initializing')) ? 'warning' : 'error') }}", + "shape": [ + "state", + { + "map": { + "success": [ + "success" + ], + "warning": [ + "warning" + ], + "error": [ + "error" + ] + } + } + ] + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/defaultContent/accessApplication.dash.json b/plugins/Cloudflare/v1/defaultContent/accessApplication.dash.json new file mode 100644 index 00000000..6f1bd8d5 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/accessApplication.dash.json @@ -0,0 +1,658 @@ +{ + "name": "Access Application", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": [ + "{{variables.[Cloudflare Access Application]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "4401425e-7e78-4997-a7f9-3bf38003f37c", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accessLogins]}}", + "name": "accessLogins", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Access Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Access Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Access Application]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count_sum", + "comparisonColumn": "none", + "label": "Logins" + } + } + }, + "timeframe": "last7days" + } + }, + { + "i": "c0679dba-38bc-4dca-b22e-d973950a66c4", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accessLogins]}}", + "name": "accessLogins", + "pluginConfigId": "{{configId}}", + "filter": { + "multiOperation": "and", + "filters": [ + { + "column": "dimensions.isSuccessfulLogin", + "operation": "equals", + "value": "true" + } + ] + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Access Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Access Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Access Application]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count_sum", + "comparisonColumn": "none", + "label": "Successful Logins" + } + } + }, + "timeframe": "last7days" + } + }, + { + "i": "b7bce084-b259-4bc6-b4e9-73315ee4573f", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accessLogins]}}", + "name": "accessLogins", + "pluginConfigId": "{{configId}}", + "filter": { + "multiOperation": "and", + "filters": [ + { + "column": "dimensions.isSuccessfulLogin", + "operation": "equals", + "value": "false" + } + ] + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Access Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Access Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Access Application]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count_sum", + "comparisonColumn": "none", + "label": "Failed Logins" + } + } + }, + "timeframe": "last7days" + } + }, + { + "i": "80cbde5c-b03f-4edf-be3b-27947acb1d86", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accessLogins]}}", + "name": "accessLogins", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "distinctCount", + "names": [ + "dimensions.country" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Access Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Access Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Access Application]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "dimensions.country_distinctCount", + "comparisonColumn": "none", + "label": "Countries" + } + } + }, + "timeframe": "last7days" + } + }, + { + "i": "14f87e15-cae4-4603-b354-8f283b6f8831", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Application Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Access Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Access Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Access Application]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "20ae9685-fe87-4ab4-8eab-f6aa4903a82a", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Logins", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accessLogins]}}", + "name": "accessLogins", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Access Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Access Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Access Application]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "count_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + }, + "timeframe": "last7days" + } + }, + { + "i": "0cb3ca1c-0d8c-4ec8-8cc9-edcdf337b9fb", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Identity Providers", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accessLogins]}}", + "name": "accessLogins", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.identityProvider", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Access Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Access Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Access Application]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count_sum", + "labelColumn": "dimensions.identityProvider_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + }, + "timeframe": "last7days" + } + }, + { + "i": "cb348c6a-6aab-44b5-864b-3808756ff226", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Logins by Country", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accessLogins]}}", + "name": "accessLogins", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.country", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Access Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Access Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Access Application]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "dimensions.country_uniqueValues", + "yAxisData": [ + "count_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + }, + "timeframe": "last7days" + } + }, + { + "i": "9f3127b2-4f9c-4fba-bb48-15796f1f093a", + "x": 0, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Login Outcomes", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accessLogins]}}", + "name": "accessLogins", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.isSuccessfulLogin", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Access Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Access Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Access Application]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count_sum", + "labelColumn": "dimensions.isSuccessfulLogin_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + }, + "timeframe": "last7days" + } + }, + { + "i": "a14fc79d-1fa7-45dd-929f-fb0b5b4790b1", + "x": 2, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "WARP Enabled", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accessLogins]}}", + "name": "accessLogins", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.hasWarpEnabled", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Access Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Access Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Access Application]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count_sum", + "labelColumn": "dimensions.hasWarpEnabled_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + }, + "timeframe": "last7days" + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/account.dash.json b/plugins/Cloudflare/v1/defaultContent/account.dash.json new file mode 100644 index 00000000..39b0634c --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/account.dash.json @@ -0,0 +1,791 @@ +{ + "name": "Account", + "schemaVersion": "1.5", + "timeframe": "none", + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "3bb95490-9698-407a-9dca-511995fe1ebb", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerScripts]}}", + "name": "workerScripts", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "count" + } + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count", + "comparisonColumn": "none", + "label": "Workers" + } + } + } + } + }, + { + "i": "eb1d6ac1-f3e8-4935-a262-59e02fac22ad", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pagesProjects]}}", + "name": "pagesProjects", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "count" + } + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count", + "comparisonColumn": "none", + "label": "Pages Projects" + } + } + } + } + }, + { + "i": "c206f73b-e9dd-4c97-8de6-153be439f5be", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[tunnels]}}", + "name": "tunnels", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "count" + } + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count", + "comparisonColumn": "none", + "label": "Tunnels" + } + } + } + } + }, + { + "i": "7f158dbb-3a69-4c68-995e-756e6d6a7d07", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[r2Buckets]}}", + "name": "r2Buckets", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "count" + } + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count", + "comparisonColumn": "none", + "label": "R2 Buckets" + } + } + } + } + }, + { + "i": "fbb27de7-9d74-4de5-aed2-8b347947c7e5", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Account Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "041c7858-722a-4e36-9e17-fa44ab609ea1", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Tunnels", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[tunnels]}}", + "name": "tunnels", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "tunnelName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "tunnelName", + "stateColumn": "status", + "sublabel": "tunnelType", + "linkColumn": "tunnelName", + "columns": 2 + } + } + } + } + }, + { + "i": "5c67e20d-99f0-4dab-b8c6-13a5f0fdf92b", + "x": 0, + "y": 5, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Workers", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerScripts]}}", + "name": "workerScripts", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "scriptName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "scriptName", + "usageModel", + "handlers", + "placementMode", + "modifiedOn" + ], + "hiddenColumns": [ + "sourceId", + "accountId", + "logpush", + "createdOn" + ] + } + } + } + } + }, + { + "i": "075c1543-3d1f-4d74-a658-dc6e19575764", + "x": 2, + "y": 5, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Pages Projects", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pagesProjects]}}", + "name": "pagesProjects", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "projectName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "projectName", + "latestDeploymentStatus", + "productionBranch", + "domains", + "latestDeploymentOn" + ], + "hiddenColumns": [ + "sourceId", + "accountId", + "subdomain", + "createdOn" + ] + } + } + } + } + }, + { + "i": "7b5a1c5b-ad5d-4cee-b6fa-4210171976e8", + "x": 0, + "y": 9, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "R2 Buckets", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[r2Buckets]}}", + "name": "r2Buckets", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "bucketName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "bucketName", + "location", + "storageClass", + "createdOn" + ], + "hiddenColumns": [ + "sourceId", + "accountId" + ] + } + } + } + } + }, + { + "i": "65d57e58-56be-42b5-86cc-735ef92fa7d8", + "x": 2, + "y": 9, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "KV Namespaces", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[kvNamespaces]}}", + "name": "kvNamespaces", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "namespaceTitle", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "namespaceTitle", + "supportsUrlEncoding" + ], + "hiddenColumns": [ + "sourceId", + "accountId" + ] + } + } + } + } + }, + { + "i": "70461624-c21e-4501-9244-23a15edd4add", + "x": 0, + "y": 13, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "D1 Databases", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[d1Databases]}}", + "name": "d1Databases", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "databaseName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "databaseName", + "numTables", + "fileSize", + "version", + "createdOn" + ], + "hiddenColumns": [ + "sourceId", + "accountId" + ] + } + } + } + } + }, + { + "i": "c25cb5ba-cd50-4a90-8871-b99f8c57bcf7", + "x": 2, + "y": 13, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Queues", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[queues]}}", + "name": "queues", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "queueName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "queueName", + "producers", + "consumers", + "modifiedOn" + ], + "hiddenColumns": [ + "sourceId", + "accountId", + "createdOn" + ] + } + } + } + } + }, + { + "i": "cd0f4644-c131-45c5-aef2-0ec8d91ca62e", + "x": 0, + "y": 17, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Load Balancer Pools", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[loadBalancerPools]}}", + "name": "loadBalancerPools", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "poolName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "poolName", + "enabled", + "originCount", + "minimumOrigins", + "modifiedOn" + ], + "hiddenColumns": [ + "sourceId", + "accountId", + "monitorId", + "createdOn" + ] + } + } + } + } + }, + { + "i": "f342d86a-84d2-4dec-999c-ef0c39f94870", + "x": 2, + "y": 17, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Access Applications", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accessApps]}}", + "name": "accessApps", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "appName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "appName", + "appType", + "domain", + "sessionDuration", + "appLauncherVisible" + ], + "hiddenColumns": [ + "sourceId", + "accountId", + "createdOn", + "modifiedOn" + ] + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/d1Database.dash.json b/plugins/Cloudflare/v1/defaultContent/d1Database.dash.json new file mode 100644 index 00000000..10c92d04 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/d1Database.dash.json @@ -0,0 +1,583 @@ +{ + "name": "D1 Database", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": [ + "{{variables.[Cloudflare D1 Database]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "b3b6d4ef-3abd-4b13-a668-39508456677c", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[d1Analytics]}}", + "name": "d1Analytics", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.readQueries" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare D1 Databases]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare D1 Database]}}" + }, + "variables": [ + "{{variables.[Cloudflare D1 Database]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.readQueries_sum", + "comparisonColumn": "none", + "label": "Read Queries" + } + } + } + } + }, + { + "i": "ce927319-f043-46a7-8947-9712d3552c9e", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[d1Analytics]}}", + "name": "d1Analytics", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.writeQueries" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare D1 Databases]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare D1 Database]}}" + }, + "variables": [ + "{{variables.[Cloudflare D1 Database]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.writeQueries_sum", + "comparisonColumn": "none", + "label": "Write Queries" + } + } + } + } + }, + { + "i": "d1d8844f-9379-45b1-a0d1-01bc5522f057", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[d1Analytics]}}", + "name": "d1Analytics", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.rowsRead" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare D1 Databases]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare D1 Database]}}" + }, + "variables": [ + "{{variables.[Cloudflare D1 Database]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.rowsRead_sum", + "comparisonColumn": "none", + "label": "Rows Read" + } + } + } + } + }, + { + "i": "caff80bd-89af-4323-8abd-cae897ff04a5", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[d1Storage]}}", + "name": "d1Storage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "max", + "names": [ + "max.databaseSizeBytes" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare D1 Databases]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare D1 Database]}}" + }, + "variables": [ + "{{variables.[Cloudflare D1 Database]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "max.databaseSizeBytes_max", + "comparisonColumn": "none", + "label": "Database Size" + } + } + } + } + }, + { + "i": "8a08f463-7e74-400b-bbf5-edb3356d59c6", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Database Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare D1 Databases]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare D1 Database]}}" + }, + "variables": [ + "{{variables.[Cloudflare D1 Database]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "a18c16cd-7ac9-4503-b5f9-b22b8d6c2db4", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Queries", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[d1Analytics]}}", + "name": "d1Analytics", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.readQueries" + ] + }, + { + "type": "sum", + "names": [ + "sum.writeQueries" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare D1 Databases]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare D1 Database]}}" + }, + "variables": [ + "{{variables.[Cloudflare D1 Database]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "sum.readQueries_sum", + "sum.writeQueries_sum" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "e6e55269-6262-4856-a3b9-412b31fc5fd3", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Rows Read and Written", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[d1Analytics]}}", + "name": "d1Analytics", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.rowsRead" + ] + }, + { + "type": "sum", + "names": [ + "sum.rowsWritten" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare D1 Databases]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare D1 Database]}}" + }, + "variables": [ + "{{variables.[Cloudflare D1 Database]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "sum.rowsRead_sum", + "sum.rowsWritten_sum" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "fb2c70e1-5fc0-4056-ab86-0a644f3a93d4", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Query Duration Percentiles", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[d1Analytics]}}", + "name": "d1Analytics", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "max", + "names": [ + "quantiles.queryBatchTimeMsP50" + ] + }, + { + "type": "max", + "names": [ + "quantiles.queryBatchTimeMsP90" + ] + }, + { + "type": "max", + "names": [ + "quantiles.queryBatchTimeMsP99" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare D1 Databases]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare D1 Database]}}" + }, + "variables": [ + "{{variables.[Cloudflare D1 Database]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "quantiles.queryBatchTimeMsP50_max", + "quantiles.queryBatchTimeMsP90_max", + "quantiles.queryBatchTimeMsP99_max" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "006437fe-9157-4629-8bf8-c1506f07dfb7", + "x": 0, + "y": 8, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Database Size", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[d1Storage]}}", + "name": "d1Storage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "max", + "names": [ + "max.databaseSizeBytes" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare D1 Databases]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare D1 Database]}}" + }, + "variables": [ + "{{variables.[Cloudflare D1 Database]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "max.databaseSizeBytes_max" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/kvNamespace.dash.json b/plugins/Cloudflare/v1/defaultContent/kvNamespace.dash.json new file mode 100644 index 00000000..64d9f234 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/kvNamespace.dash.json @@ -0,0 +1,566 @@ +{ + "name": "KV Namespace", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": [ + "{{variables.[Cloudflare KV Namespace]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "64a2bb14-0f54-429e-b74a-49f677e78258", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[kvOperations]}}", + "name": "kvOperations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare KV Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare KV Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare KV Namespace]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.requests_sum", + "comparisonColumn": "none", + "label": "Requests" + } + } + } + } + }, + { + "i": "c416ec31-0ba0-495a-a408-4426dee9a026", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[kvStorage]}}", + "name": "kvStorage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "max", + "names": [ + "max.keyCount" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare KV Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare KV Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare KV Namespace]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "max.keyCount_max", + "comparisonColumn": "none", + "label": "Keys" + } + } + } + } + }, + { + "i": "3999ca4b-3aa6-441b-83a4-8a2882d9eaa2", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[kvStorage]}}", + "name": "kvStorage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "max", + "names": [ + "max.byteCount" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare KV Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare KV Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare KV Namespace]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "max.byteCount_max", + "comparisonColumn": "none", + "label": "Stored Bytes" + } + } + } + } + }, + { + "i": "a03c3ae0-9707-4c25-8543-c96f23ead83c", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[kvOperations]}}", + "name": "kvOperations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "max", + "names": [ + "quantiles.latencyMsP99" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare KV Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare KV Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare KV Namespace]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "quantiles.latencyMsP99_max", + "comparisonColumn": "none", + "label": "Peak Latency P99" + } + } + } + } + }, + { + "i": "8ac4f1cd-177a-4ce0-b9fc-4bb2f9ae33f8", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Namespace Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare KV Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare KV Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare KV Namespace]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "8819f11c-eda9-4536-a767-274c8fac5c4f", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Requests", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[kvOperations]}}", + "name": "kvOperations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare KV Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare KV Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare KV Namespace]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "sum.requests_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "6ee4337c-c1d0-4a60-84bd-632a00b2eb30", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Requests by Operation", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[kvOperations]}}", + "name": "kvOperations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.actionType", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "sum.requests_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare KV Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare KV Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare KV Namespace]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "sum.requests_sum", + "labelColumn": "dimensions.actionType_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "306acd99-f66d-4a0f-b808-e6c616b0f160", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Latency Percentiles", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[kvOperations]}}", + "name": "kvOperations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "max", + "names": [ + "quantiles.latencyMsP50" + ] + }, + { + "type": "max", + "names": [ + "quantiles.latencyMsP90" + ] + }, + { + "type": "max", + "names": [ + "quantiles.latencyMsP99" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare KV Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare KV Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare KV Namespace]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "quantiles.latencyMsP50_max", + "quantiles.latencyMsP90_max", + "quantiles.latencyMsP99_max" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "3858229c-8507-48ae-bb01-78eec18757f1", + "x": 0, + "y": 8, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Key Count", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[kvStorage]}}", + "name": "kvStorage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "max", + "names": [ + "max.keyCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare KV Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare KV Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare KV Namespace]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "max.keyCount_max" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/loadBalancerPool.dash.json b/plugins/Cloudflare/v1/defaultContent/loadBalancerPool.dash.json new file mode 100644 index 00000000..2c83d63f --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/loadBalancerPool.dash.json @@ -0,0 +1,379 @@ +{ + "name": "Load Balancer Pool", + "schemaVersion": "1.5", + "timeframe": "none", + "variables": [ + "{{variables.[Cloudflare Load Balancer Pool]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "fb17591a-54bb-4977-a18f-b38393ed1d7d", + "x": 0, + "y": 0, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Pool Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Load Balancer Pools]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Load Balancer Pool]}}" + }, + "variables": [ + "{{variables.[Cloudflare Load Balancer Pool]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "7607c0c4-39ca-4249-b378-97656e6bb18c", + "x": 2, + "y": 0, + "w": 1, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[loadBalancerPoolHealth]}}", + "name": "loadBalancerPoolHealth", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "count" + } + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Load Balancer Pools]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Load Balancer Pool]}}" + }, + "variables": [ + "{{variables.[Cloudflare Load Balancer Pool]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count", + "comparisonColumn": "none", + "label": "Origin Checks" + } + } + } + } + }, + { + "i": "8d2a035e-d20f-44c2-b7f8-b0527bcd6dc3", + "x": 3, + "y": 0, + "w": 1, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[loadBalancerPoolHealth]}}", + "name": "loadBalancerPoolHealth", + "pluginConfigId": "{{configId}}", + "filter": { + "multiOperation": "and", + "filters": [ + { + "column": "healthy", + "operation": "equals", + "value": "false" + } + ] + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "count" + } + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Load Balancer Pools]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Load Balancer Pool]}}" + }, + "variables": [ + "{{variables.[Cloudflare Load Balancer Pool]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count", + "comparisonColumn": "none", + "label": "Unhealthy Checks" + } + } + } + } + }, + { + "i": "e1e6ceb8-d7a1-4a9e-a9a3-460fde989299", + "x": 0, + "y": 3, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Health Check Results", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[loadBalancerPoolHealth]}}", + "name": "loadBalancerPoolHealth", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "healthy", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "count" + } + ] + }, + "sort": { + "by": [ + [ + "count", + "desc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Load Balancer Pools]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Load Balancer Pool]}}" + }, + "variables": [ + "{{variables.[Cloudflare Load Balancer Pool]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count", + "labelColumn": "healthy_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "6b84a7bd-0dbc-4a62-99e6-58f8851bd5e3", + "x": 2, + "y": 3, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Checks by Data Centre", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[loadBalancerPoolHealth]}}", + "name": "loadBalancerPoolHealth", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "colo", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "count" + } + ] + }, + "sort": { + "by": [ + [ + "count", + "desc" + ] + ], + "top": 15 + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Load Balancer Pools]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Load Balancer Pool]}}" + }, + "variables": [ + "{{variables.[Cloudflare Load Balancer Pool]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "colo_uniqueValues", + "yAxisData": [ + "count" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "88076a78-f154-4ac7-8a32-fd581d9fb2b5", + "x": 0, + "y": 6, + "w": 4, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Origin Health", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[loadBalancerPoolHealth]}}", + "name": "loadBalancerPoolHealth", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "healthy", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Load Balancer Pools]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Load Balancer Pool]}}" + }, + "variables": [ + "{{variables.[Cloudflare Load Balancer Pool]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "colo", + "origin", + "healthy", + "responseCode", + "rtt", + "failureReason" + ], + "hiddenColumns": [ + "coloHealthy" + ] + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/manifest.json b/plugins/Cloudflare/v1/defaultContent/manifest.json new file mode 100644 index 00000000..74187074 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/manifest.json @@ -0,0 +1,52 @@ +{ + "items": [ + { + "name": "overview", + "type": "dashboard" + }, + { + "name": "account", + "type": "dashboard" + }, + { + "name": "zone", + "type": "dashboard" + }, + { + "name": "worker", + "type": "dashboard" + }, + { + "name": "r2Bucket", + "type": "dashboard" + }, + { + "name": "pagesProject", + "type": "dashboard" + }, + { + "name": "d1Database", + "type": "dashboard" + }, + { + "name": "kvNamespace", + "type": "dashboard" + }, + { + "name": "queue", + "type": "dashboard" + }, + { + "name": "tunnel", + "type": "dashboard" + }, + { + "name": "loadBalancerPool", + "type": "dashboard" + }, + { + "name": "accessApplication", + "type": "dashboard" + } + ] +} diff --git a/plugins/Cloudflare/v1/defaultContent/overview.dash.json b/plugins/Cloudflare/v1/defaultContent/overview.dash.json new file mode 100644 index 00000000..d95b0659 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/overview.dash.json @@ -0,0 +1,1189 @@ +{ + "name": "Overview", + "schemaVersion": "1.5", + "timeframe": "none", + "variables": [], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "ccf7079b-045c-4bd3-b7b1-52d6bc2e77a0", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": { + "type": "count" + }, + "comparisonColumn": "none", + "label": "Accounts" + } + } + } + } + }, + { + "i": "4bcccd3d-38e3-4f95-97e2-6447e9d902f4", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": { + "type": "count" + }, + "comparisonColumn": "none", + "label": "Zones" + } + } + } + } + }, + { + "i": "9861c8c5-2f72-4d6e-a15e-a77870b994c1", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Workers]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": { + "type": "count" + }, + "comparisonColumn": "none", + "label": "Workers" + } + } + } + } + }, + { + "i": "d22c9705-97e7-4a7c-b159-fa8c155fdd98", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Pages Projects]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": { + "type": "count" + }, + "comparisonColumn": "none", + "label": "Pages Projects" + } + } + } + } + }, + { + "i": "8868fd1a-1a18-4e3a-abca-eef5fa86f038", + "x": 0, + "y": 2, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare R2 Buckets]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": { + "type": "count" + }, + "comparisonColumn": "none", + "label": "R2 Buckets" + } + } + } + } + }, + { + "i": "75f080ca-6ba8-4c2c-ade9-91a7d1600472", + "x": 1, + "y": 2, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare KV Namespaces]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": { + "type": "count" + }, + "comparisonColumn": "none", + "label": "KV Namespaces" + } + } + } + } + }, + { + "i": "9e250b2d-8c02-4770-aad5-99536906389b", + "x": 2, + "y": 2, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare D1 Databases]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": { + "type": "count" + }, + "comparisonColumn": "none", + "label": "D1 Databases" + } + } + } + } + }, + { + "i": "3dd81119-7ee0-4d0f-a712-53445e92bdf7", + "x": 3, + "y": 2, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Queues]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": { + "type": "count" + }, + "comparisonColumn": "none", + "label": "Queues" + } + } + } + } + }, + { + "i": "9de616f8-033c-42af-9d1e-e2a78123bd73", + "x": 0, + "y": 4, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Tunnels]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": { + "type": "count" + }, + "comparisonColumn": "none", + "label": "Tunnels" + } + } + } + } + }, + { + "i": "38f82716-36d7-4c6e-94a7-23802d910c96", + "x": 1, + "y": 4, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Load Balancer Pools]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": { + "type": "count" + }, + "comparisonColumn": "none", + "label": "Load Balancer Pools" + } + } + } + } + }, + { + "i": "0deace6d-08ad-4289-8631-f1e13fa67c57", + "x": 2, + "y": 4, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Access Applications]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": { + "type": "count" + }, + "comparisonColumn": "none", + "label": "Access Applications" + } + } + } + } + }, + { + "i": "fdac72fb-6dbc-4fe0-af7f-609f5a8bb33e", + "x": 3, + "y": 4, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "filter": { + "multiOperation": "and", + "filters": [ + { + "column": "paused", + "operation": "equals", + "value": "true" + } + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": { + "type": "count" + }, + "comparisonColumn": "none", + "label": "Zones Paused" + } + } + } + } + }, + { + "i": "01071810-2460-4d6f-ac37-2d8c6c78ace3", + "x": 0, + "y": 6, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Zones by Status", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "group": { + "by": [ + [ + "status", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "count" + } + ] + }, + "sort": { + "by": [ + [ + "count", + "desc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count", + "labelColumn": "status_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "06de4718-8250-4cc0-b864-1d9cc11c1394", + "x": 2, + "y": 6, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Zones by Plan", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "group": { + "by": [ + [ + "planName", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "count" + } + ] + }, + "sort": { + "by": [ + [ + "count", + "desc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count", + "labelColumn": "planName_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "6b70dcfc-f6fe-4f22-a57c-7fa7fa23be9c", + "x": 0, + "y": 9, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Zones", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "status", + "sublabel": "planName", + "linkColumn": "link", + "columns": 4, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "2bbc6141-d374-41c7-93b1-3b3f7677c193", + "x": 0, + "y": 12, + "w": 4, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Zone Inventory", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "name", + "status", + "planName", + "accountName", + "zoneType", + "developmentModeActive", + "activatedOn" + ], + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type", + "sourceType", + "accountId", + "paused", + "createdOn", + "nameServers" + ], + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "5be40674-431e-465f-94fc-3b658438dc77", + "x": 0, + "y": 16, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Workers", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Workers]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "usageModel", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "f51e9fdc-9a9e-4272-b24d-9d5d11eac793", + "x": 2, + "y": 16, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Pages Projects", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Pages Projects]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "latestDeploymentStatus", + "sublabel": "productionBranch", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "f2587bfd-deef-45ac-9501-1d66bf9c7734", + "x": 0, + "y": 19, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Tunnels", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Tunnels]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "status", + "sublabel": "tunnelType", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "af6eee0c-cfbf-43e1-a51c-53dca0e9a356", + "x": 2, + "y": 19, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Load Balancer Pools", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Load Balancer Pools]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "9beee6df-b954-4c3f-9c99-dd09a66a3f6a", + "x": 0, + "y": 22, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "R2 Buckets", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare R2 Buckets]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "location", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "c6e175b9-164a-4b14-a4a2-22312083c04f", + "x": 2, + "y": 22, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "D1 Databases", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare D1 Databases]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "62ced3d6-e538-4573-af2c-24365a1d7b52", + "x": 0, + "y": 25, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "KV Namespaces", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare KV Namespaces]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "4a7ce999-9bb4-48f9-890d-6d6dcb4d5e49", + "x": 2, + "y": 25, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Queues", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Queues]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "0db6f61a-dc9f-499c-bd92-b863f2cc9eed", + "x": 0, + "y": 28, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Access Applications", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Access Applications]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "domain", + "linkColumn": "link", + "columns": 4, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/pagesProject.dash.json b/plugins/Cloudflare/v1/defaultContent/pagesProject.dash.json new file mode 100644 index 00000000..1a0fa291 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/pagesProject.dash.json @@ -0,0 +1,309 @@ +{ + "name": "Pages Project", + "schemaVersion": "1.5", + "timeframe": "none", + "variables": [ + "{{variables.[Cloudflare Pages Project]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "24e8166d-ea90-45bf-a4de-8df7dd9033a3", + "x": 0, + "y": 0, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Project Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Pages Projects]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Pages Project]}}" + }, + "variables": [ + "{{variables.[Cloudflare Pages Project]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "62a4eba1-b082-4a4d-b8d3-7bb6f3bab970", + "x": 2, + "y": 0, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Latest Deployments", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pagesDeployments]}}", + "name": "pagesDeployments", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "created_on", + "desc" + ] + ], + "top": 8 + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Pages Projects]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Pages Project]}}" + }, + "variables": [ + "{{variables.[Cloudflare Pages Project]}}" + ], + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "short_id", + "stateColumn": "status", + "sublabel": "branch", + "linkColumn": "none", + "columns": 4 + } + } + } + } + }, + { + "i": "92727f98-b5b9-42ec-b67c-6872f87afbe2", + "x": 0, + "y": 3, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Deployments by Status", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pagesDeployments]}}", + "name": "pagesDeployments", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "status", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "count" + } + ] + }, + "sort": { + "by": [ + [ + "count", + "desc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Pages Projects]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Pages Project]}}" + }, + "variables": [ + "{{variables.[Cloudflare Pages Project]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count", + "labelColumn": "status_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "6dec82d4-05e1-4196-abd9-01ff6537d2b3", + "x": 2, + "y": 3, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Deployments by Environment", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pagesDeployments]}}", + "name": "pagesDeployments", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "environment", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "count" + } + ] + }, + "sort": { + "by": [ + [ + "count", + "desc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Pages Projects]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Pages Project]}}" + }, + "variables": [ + "{{variables.[Cloudflare Pages Project]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count", + "labelColumn": "environment_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "f5f618a9-bf99-4fee-b0e9-b1d8ac9d4c98", + "x": 0, + "y": 6, + "w": 4, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Deployment History", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pagesDeployments]}}", + "name": "pagesDeployments", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "created_on", + "desc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Pages Projects]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Pages Project]}}" + }, + "variables": [ + "{{variables.[Cloudflare Pages Project]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "created_on", + "short_id", + "environment", + "status", + "branch", + "commitMessage", + "url" + ], + "hiddenColumns": [ + "stage", + "commit" + ] + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/queue.dash.json b/plugins/Cloudflare/v1/defaultContent/queue.dash.json new file mode 100644 index 00000000..997c8dd2 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/queue.dash.json @@ -0,0 +1,549 @@ +{ + "name": "Queue", + "schemaVersion": "1.5", + "timeframe": "last24hours", + "variables": [ + "{{variables.[Cloudflare Queue]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "0c25a196-d3d7-4945-aab7-a08f510790aa", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[queueMessageOperations]}}", + "name": "queueMessageOperations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Queues]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Queue]}}" + }, + "variables": [ + "{{variables.[Cloudflare Queue]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count_sum", + "comparisonColumn": "none", + "label": "Message Operations" + } + } + } + } + }, + { + "i": "9c61aaea-eacc-46aa-a072-eed3aab9cdca", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[queueMessageOperations]}}", + "name": "queueMessageOperations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.billableOperations" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Queues]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Queue]}}" + }, + "variables": [ + "{{variables.[Cloudflare Queue]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.billableOperations_sum", + "comparisonColumn": "none", + "label": "Billable Operations" + } + } + } + } + }, + { + "i": "d6623bf7-9039-4a45-8cb0-156767366d77", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[queueMessageOperations]}}", + "name": "queueMessageOperations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.bytes" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Queues]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Queue]}}" + }, + "variables": [ + "{{variables.[Cloudflare Queue]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.bytes_sum", + "comparisonColumn": "none", + "label": "Bytes Processed" + } + } + } + } + }, + { + "i": "168c58fe-418a-416f-b086-075fcd059da7", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[queueBacklog]}}", + "name": "queueBacklog", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "mean", + "names": [ + "avg.messages" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Queues]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Queue]}}" + }, + "variables": [ + "{{variables.[Cloudflare Queue]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "avg.messages_mean", + "comparisonColumn": "none", + "label": "Average Backlog" + } + } + } + } + }, + { + "i": "32d2ad5e-db49-434d-9176-023fbd0da69b", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Queue Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Queues]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Queue]}}" + }, + "variables": [ + "{{variables.[Cloudflare Queue]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "cad9a0ff-d149-46a2-aa27-8d10eee737da", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Backlog", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[queueBacklog]}}", + "name": "queueBacklog", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetimeHour", + "byHour" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "avg.messages" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.datetimeHour_byHour", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Queues]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Queue]}}" + }, + "variables": [ + "{{variables.[Cloudflare Queue]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetimeHour_byHour", + "yAxisColumn": [ + "avg.messages_mean" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "2d7beb77-32be-4243-9636-0af143ad80c9", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Operations by Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[queueMessageOperations]}}", + "name": "queueMessageOperations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.actionType", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Queues]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Queue]}}" + }, + "variables": [ + "{{variables.[Cloudflare Queue]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count_sum", + "labelColumn": "dimensions.actionType_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "9a3fa9e9-3dec-4c02-966a-505a537b2f36", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Operation Outcomes", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[queueMessageOperations]}}", + "name": "queueMessageOperations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.outcome", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Queues]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Queue]}}" + }, + "variables": [ + "{{variables.[Cloudflare Queue]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count_sum", + "labelColumn": "dimensions.outcome_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "5ba07096-3905-4a6d-872e-60cc09ded22b", + "x": 0, + "y": 8, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Message Lag Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[queueMessageOperations]}}", + "name": "queueMessageOperations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetimeHour", + "byHour" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "avg.lagTime" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.datetimeHour_byHour", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Queues]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Queue]}}" + }, + "variables": [ + "{{variables.[Cloudflare Queue]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetimeHour_byHour", + "yAxisColumn": [ + "avg.lagTime_mean" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/r2Bucket.dash.json b/plugins/Cloudflare/v1/defaultContent/r2Bucket.dash.json new file mode 100644 index 00000000..4aa715a4 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/r2Bucket.dash.json @@ -0,0 +1,564 @@ +{ + "name": "R2 Bucket", + "schemaVersion": "1.5", + "timeframe": "last24hours", + "variables": [ + "{{variables.[Cloudflare R2 Bucket]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "0386adc1-d8ee-4ff1-af52-bf5db3b3aba7", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[r2Operations]}}", + "name": "r2Operations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare R2 Buckets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare R2 Bucket]}}" + }, + "variables": [ + "{{variables.[Cloudflare R2 Bucket]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.requests_sum", + "comparisonColumn": "none", + "label": "Requests" + } + } + } + } + }, + { + "i": "31cbee1e-67d6-4f02-b9b0-53429d52e24f", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[r2Operations]}}", + "name": "r2Operations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.responseBytes" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare R2 Buckets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare R2 Bucket]}}" + }, + "variables": [ + "{{variables.[Cloudflare R2 Bucket]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.responseBytes_sum", + "comparisonColumn": "none", + "label": "Data Transferred" + } + } + } + } + }, + { + "i": "eb6479e5-2310-4e23-87fb-0e06242866aa", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[r2Storage]}}", + "name": "r2Storage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "max", + "names": [ + "max.objectCount" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare R2 Buckets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare R2 Bucket]}}" + }, + "variables": [ + "{{variables.[Cloudflare R2 Bucket]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "max.objectCount_max", + "comparisonColumn": "none", + "label": "Objects" + } + } + } + } + }, + { + "i": "6fa534a8-06df-4790-a0d5-694db1416e00", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[r2Storage]}}", + "name": "r2Storage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "max", + "names": [ + "max.payloadSize" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare R2 Buckets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare R2 Bucket]}}" + }, + "variables": [ + "{{variables.[Cloudflare R2 Bucket]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "max.payloadSize_max", + "comparisonColumn": "none", + "label": "Stored Bytes" + } + } + } + } + }, + { + "i": "f38bfdfd-8422-45d6-bbe1-a810bae04dcc", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Bucket Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare R2 Buckets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare R2 Bucket]}}" + }, + "variables": [ + "{{variables.[Cloudflare R2 Bucket]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "3a538ff6-f36c-4e48-8efa-ea8663576376", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Operations", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[r2Operations]}}", + "name": "r2Operations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetime", + "byHour" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.datetime_byHour", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare R2 Buckets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare R2 Bucket]}}" + }, + "variables": [ + "{{variables.[Cloudflare R2 Bucket]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byHour", + "yAxisColumn": [ + "sum.requests_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "a0c48140-ad87-4aa2-9023-1119f1f7391c", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Operations by Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[r2Operations]}}", + "name": "r2Operations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.actionType", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "sum.requests_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare R2 Buckets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare R2 Bucket]}}" + }, + "variables": [ + "{{variables.[Cloudflare R2 Bucket]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "dimensions.actionType_uniqueValues", + "yAxisData": [ + "sum.requests_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "e3a08ccf-45a3-48e3-98a6-2a50b444ab6d", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Operations by Status", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[r2Operations]}}", + "name": "r2Operations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.actionStatus", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "sum.requests_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare R2 Buckets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare R2 Bucket]}}" + }, + "variables": [ + "{{variables.[Cloudflare R2 Bucket]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "sum.requests_sum", + "labelColumn": "dimensions.actionStatus_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "ac43e3d1-d7e6-4341-aa16-0c741fa39b9d", + "x": 0, + "y": 8, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Stored Bytes", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[r2Storage]}}", + "name": "r2Storage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetime", + "byHour" + ] + ], + "aggregate": [ + { + "type": "max", + "names": [ + "max.payloadSize" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.datetime_byHour", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare R2 Buckets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare R2 Bucket]}}" + }, + "variables": [ + "{{variables.[Cloudflare R2 Bucket]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byHour", + "yAxisColumn": [ + "max.payloadSize_max" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/scopes.json b/plugins/Cloudflare/v1/defaultContent/scopes.json new file mode 100644 index 00000000..60f3ea56 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/scopes.json @@ -0,0 +1,189 @@ +[ + { + "name": "Cloudflare Accounts", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "variable": { + "name": "Cloudflare Account", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare Zones", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Zone" + ] + } + }, + "variable": { + "name": "Cloudflare Zone", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare Workers", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Worker" + ] + } + }, + "variable": { + "name": "Cloudflare Worker", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare R2 Buckets", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare R2 Bucket" + ] + } + }, + "variable": { + "name": "Cloudflare R2 Bucket", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare Pages Projects", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Pages Project" + ] + } + }, + "variable": { + "name": "Cloudflare Pages Project", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare D1 Databases", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare D1 Database" + ] + } + }, + "variable": { + "name": "Cloudflare D1 Database", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare KV Namespaces", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare KV Namespace" + ] + } + }, + "variable": { + "name": "Cloudflare KV Namespace", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare Queues", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Queue" + ] + } + }, + "variable": { + "name": "Cloudflare Queue", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare Tunnels", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Tunnel" + ] + } + }, + "variable": { + "name": "Cloudflare Tunnel", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare Load Balancer Pools", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Load Balancer Pool" + ] + } + }, + "variable": { + "name": "Cloudflare Load Balancer Pool", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare Access Applications", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Access Application" + ] + } + }, + "variable": { + "name": "Cloudflare Access Application", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + } +] diff --git a/plugins/Cloudflare/v1/defaultContent/tunnel.dash.json b/plugins/Cloudflare/v1/defaultContent/tunnel.dash.json new file mode 100644 index 00000000..ca7a93fd --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/tunnel.dash.json @@ -0,0 +1,306 @@ +{ + "name": "Tunnel", + "schemaVersion": "1.5", + "timeframe": "none", + "variables": [ + "{{variables.[Cloudflare Tunnel]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "e0ced236-ba52-475b-808a-4ee02f0678e3", + "x": 0, + "y": 0, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Tunnel Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Tunnels]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Tunnel]}}" + }, + "variables": [ + "{{variables.[Cloudflare Tunnel]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "49a68abf-e454-4c27-83e2-c5eee8ee4251", + "x": 2, + "y": 0, + "w": 1, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[tunnelConnections]}}", + "name": "tunnelConnections", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "count" + } + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Tunnels]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Tunnel]}}" + }, + "variables": [ + "{{variables.[Cloudflare Tunnel]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count", + "comparisonColumn": "none", + "label": "Connections" + } + } + } + } + }, + { + "i": "6119da2c-122c-47ad-ba03-919723c9b3e8", + "x": 3, + "y": 0, + "w": 1, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[tunnelConnections]}}", + "name": "tunnelConnections", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "distinctCount", + "names": [ + "colo_name" + ] + } + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Tunnels]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Tunnel]}}" + }, + "variables": [ + "{{variables.[Cloudflare Tunnel]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "colo_name_distinctCount", + "comparisonColumn": "none", + "label": "Data Centres" + } + } + } + } + }, + { + "i": "181cf765-7d39-4ce6-a272-cc80cdf5cbcd", + "x": 0, + "y": 3, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Connections by Data Centre", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[tunnelConnections]}}", + "name": "tunnelConnections", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "colo_name", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "count" + } + ] + }, + "sort": { + "by": [ + [ + "count", + "desc" + ] + ], + "top": 15 + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Tunnels]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Tunnel]}}" + }, + "variables": [ + "{{variables.[Cloudflare Tunnel]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "colo_name_uniqueValues", + "yAxisData": [ + "count" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "d39022b4-50e5-4c24-8bd6-435bea7475bb", + "x": 0, + "y": 6, + "w": 4, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Connections", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[tunnelConnections]}}", + "name": "tunnelConnections", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "opened_at", + "desc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Tunnels]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Tunnel]}}" + }, + "variables": [ + "{{variables.[Cloudflare Tunnel]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "colo_name", + "origin_ip", + "client_version", + "arch", + "opened_at", + "is_pending_reconnect" + ], + "hiddenColumns": [ + "connectionId" + ] + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/worker.dash.json b/plugins/Cloudflare/v1/defaultContent/worker.dash.json new file mode 100644 index 00000000..1cb6ec5c --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/worker.dash.json @@ -0,0 +1,495 @@ +{ + "name": "Worker", + "schemaVersion": "1.5", + "timeframe": "last24hours", + "variables": [ + "{{variables.[Cloudflare Worker]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "33449361-5fba-44c2-acf9-a2d93dbc965d", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerInvocations]}}", + "name": "workerInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Workers]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Worker]}}" + }, + "variables": [ + "{{variables.[Cloudflare Worker]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.requests_sum", + "comparisonColumn": "none", + "label": "Requests" + } + } + } + } + }, + { + "i": "5e2b36e7-3b7c-483e-9d70-616f6cff6f5d", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerInvocations]}}", + "name": "workerInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.errors" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Workers]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Worker]}}" + }, + "variables": [ + "{{variables.[Cloudflare Worker]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.errors_sum", + "comparisonColumn": "none", + "label": "Errors" + } + } + } + } + }, + { + "i": "83e50375-26f8-41be-9bcd-06d9e524535c", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerInvocations]}}", + "name": "workerInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.subrequests" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Workers]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Worker]}}" + }, + "variables": [ + "{{variables.[Cloudflare Worker]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.subrequests_sum", + "comparisonColumn": "none", + "label": "Subrequests" + } + } + } + } + }, + { + "i": "66fc75ed-e3b8-4ff2-823e-395620d34ef8", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerInvocations]}}", + "name": "workerInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "max", + "names": [ + "cpuTimeP99Ms" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Workers]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Worker]}}" + }, + "variables": [ + "{{variables.[Cloudflare Worker]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "cpuTimeP99Ms_max", + "comparisonColumn": "none", + "label": "Peak CPU Time P99" + } + } + } + } + }, + { + "i": "a983183c-4266-487b-aee8-9bf5744a2511", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Worker Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Workers]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Worker]}}" + }, + "variables": [ + "{{variables.[Cloudflare Worker]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "63e94747-153e-48ef-890d-0715068f0a6f", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Requests and Errors", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerInvocations]}}", + "name": "workerInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetime", + "byHour" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + }, + { + "type": "sum", + "names": [ + "sum.errors" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.datetime_byHour", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Workers]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Worker]}}" + }, + "variables": [ + "{{variables.[Cloudflare Worker]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byHour", + "yAxisColumn": [ + "sum.requests_sum", + "sum.errors_sum" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "f33635f4-95d8-4be4-ae07-89a39e533326", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "CPU Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerInvocations]}}", + "name": "workerInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetime", + "byHour" + ] + ], + "aggregate": [ + { + "type": "max", + "names": [ + "cpuTimeP50Ms" + ] + }, + { + "type": "max", + "names": [ + "cpuTimeP99Ms" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.datetime_byHour", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Workers]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Worker]}}" + }, + "variables": [ + "{{variables.[Cloudflare Worker]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byHour", + "yAxisColumn": [ + "cpuTimeP50Ms_max", + "cpuTimeP99Ms_max" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "73f51ba3-4dae-499c-8c26-5fbaf6c9c9fa", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Invocations by Status", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerInvocations]}}", + "name": "workerInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.status", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "sum.requests_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Workers]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Worker]}}" + }, + "variables": [ + "{{variables.[Cloudflare Worker]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "sum.requests_sum", + "labelColumn": "dimensions.status_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/zone.dash.json b/plugins/Cloudflare/v1/defaultContent/zone.dash.json new file mode 100644 index 00000000..d09483d3 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/zone.dash.json @@ -0,0 +1,1343 @@ +{ + "name": "Zone", + "schemaVersion": "1.5", + "timeframe": "last24hours", + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "dbbd193c-5a10-4b49-8a2b-f33b1fe54efe", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTraffic]}}", + "name": "zoneTraffic", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.requests_sum", + "comparisonColumn": "none", + "label": "Requests" + } + } + } + } + }, + { + "i": "359ed863-1182-4dea-8299-3ed8a3b75b22", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTraffic]}}", + "name": "zoneTraffic", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "uniq.uniques" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "uniq.uniques_sum", + "comparisonColumn": "none", + "label": "Unique Visitors" + } + } + } + } + }, + { + "i": "1cac5d62-0609-4166-9ead-ba20f448f830", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTraffic]}}", + "name": "zoneTraffic", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.bytes" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.bytes_sum", + "comparisonColumn": "none", + "label": "Bandwidth" + } + } + } + } + }, + { + "i": "2d0590e9-4c6b-460d-8919-c2658524e750", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTraffic]}}", + "name": "zoneTraffic", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.threats" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.threats_sum", + "comparisonColumn": "none", + "label": "Threats" + } + } + } + } + }, + { + "i": "a73efcb0-71d7-4148-91c5-56edd3518568", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Zone Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "4b177d07-939f-4a35-9b5b-d47d7cad13c8", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Requests", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTraffic]}}", + "name": "zoneTraffic", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime", + "yAxisColumn": [ + "sum.requests", + "sum.cachedRequests" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "2b949c2a-6bd1-480b-8b02-78ae669d7be4", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Bandwidth", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTraffic]}}", + "name": "zoneTraffic", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime", + "yAxisColumn": [ + "sum.bytes", + "sum.cachedBytes" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "2ce8c81d-92e5-4e30-b1fb-95a45e1c567d", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Cache Hit Ratio", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTraffic]}}", + "name": "zoneTraffic", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime", + "yAxisColumn": [ + "cacheHitRatio" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "8a7c2e43-e5a1-4fb8-a862-3bf8ec9f364d", + "x": 0, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Traffic by Country", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTrafficBreakdown]}}", + "name": "zoneTrafficBreakdown", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "clientCountryName" + }, + "sort": { + "by": [ + [ + "requests", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown", + "yAxisData": [ + "requests" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "babb40cf-e759-4887-8474-8649bfc1a846", + "x": 2, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Traffic by Status Code", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTrafficBreakdown]}}", + "name": "zoneTrafficBreakdown", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "edgeResponseStatus" + }, + "sort": { + "by": [ + [ + "requests", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "requests", + "labelColumn": "breakdown", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "5c613d78-1252-432a-b699-9064fe5625bc", + "x": 0, + "y": 11, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Cache Status", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTrafficBreakdown]}}", + "name": "zoneTrafficBreakdown", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "cacheStatus" + }, + "sort": { + "by": [ + [ + "requests", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "requests", + "labelColumn": "breakdown", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "fb685bc2-f0f1-4d13-b965-4852d361d7bc", + "x": 2, + "y": 11, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Traffic by Device Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTrafficBreakdown]}}", + "name": "zoneTrafficBreakdown", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "clientDeviceType" + }, + "sort": { + "by": [ + [ + "requests", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "requests", + "labelColumn": "breakdown", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "b5b428c0-6e8b-4b20-8637-826523d8875e", + "x": 0, + "y": 14, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Firewall Events by Rule", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneFirewallEvents]}}", + "name": "zoneFirewallEvents", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "ruleId" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "events" + ] + } + ] + }, + "sort": { + "by": [ + [ + "events_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "events_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "f70d4a4d-aa25-436e-bc2d-f57913923742", + "x": 2, + "y": 14, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Firewall Events by Service", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneFirewallEvents]}}", + "name": "zoneFirewallEvents", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "source" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "events" + ] + } + ] + }, + "sort": { + "by": [ + [ + "events_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "events_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "ab07298c-beb2-45ad-ab55-973b5ee13c9e", + "x": 0, + "y": 17, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Firewall Events by Country", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneFirewallEvents]}}", + "name": "zoneFirewallEvents", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "clientCountryName" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "events" + ] + } + ] + }, + "sort": { + "by": [ + [ + "events_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "events_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "36980a5b-9966-4da8-b4ae-03a64c40c648", + "x": 2, + "y": 17, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Firewall Actions", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneFirewallEvents]}}", + "name": "zoneFirewallEvents", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "source" + }, + "group": { + "by": [ + [ + "action", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "events" + ] + } + ] + }, + "sort": { + "by": [ + [ + "events_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "events_sum", + "labelColumn": "action_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "6084f30d-d547-4fdf-8712-6ac71b5fb03a", + "x": 0, + "y": 20, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "SSL Certificates", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneCertificates]}}", + "name": "zoneCertificates", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "daysUntilExpiry", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "hosts", + "status", + "daysUntilExpiry", + "expiresOn", + "certificateAuthority", + "type" + ], + "hiddenColumns": [ + "id", + "issuer", + "validationMethod" + ] + } + } + } + } + }, + { + "i": "b32501ab-3b1e-47da-bb9c-19fab121891f", + "x": 2, + "y": 20, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Health Checks", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneHealthChecks]}}", + "name": "zoneHealthChecks", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "name", + "status", + "address", + "type", + "failure_reason", + "suspended" + ], + "hiddenColumns": [ + "id", + "interval", + "timeout", + "consecutive_fails", + "consecutive_successes", + "check_regions", + "created_on", + "modified_on" + ] + } + } + } + } + }, + { + "i": "2a5caeac-bbae-4322-934c-4a58f34091f0", + "x": 0, + "y": 24, + "w": 4, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "DNS Records", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneDnsRecords]}}", + "name": "zoneDnsRecords", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "name", + "type", + "content", + "proxied", + "ttl", + "comment" + ], + "hiddenColumns": [ + "id", + "tags", + "created_on", + "modified_on" + ] + } + } + } + } + }, + { + "i": "4340f0d4-7cb2-495e-a086-4b115ac7eede", + "x": 0, + "y": 28, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Load Balancing by Pool", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneLoadBalancing]}}", + "name": "zoneLoadBalancing", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.selectedPoolName", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "dimensions.selectedPoolName_uniqueValues", + "yAxisData": [ + "count_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "d0c74ae9-3aca-4708-a4a1-373db8a88696", + "x": 2, + "y": 28, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Load Balancing by Origin", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneLoadBalancing]}}", + "name": "zoneLoadBalancing", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.selectedOriginName", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "dimensions.selectedOriginName_uniqueValues", + "yAxisData": [ + "count_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/docs/README.md b/plugins/Cloudflare/v1/docs/README.md new file mode 100644 index 00000000..5a0830c1 --- /dev/null +++ b/plugins/Cloudflare/v1/docs/README.md @@ -0,0 +1,140 @@ +Monitor your [Cloudflare](https://www.cloudflare.com) account in SquaredUp - zone traffic and cache performance, firewall and WAF activity, DNS records and SSL certificate expiry, plus the developer platform: Workers, R2, KV, D1, Queues, Pages, Tunnels, Load Balancers and Access applications. Data comes from the [Cloudflare REST API](https://developers.cloudflare.com/api/) and the [GraphQL Analytics API](https://developers.cloudflare.com/analytics/graphql-api/). + +> ⚠️ This plugin is **read-only** and never changes anything in your Cloudflare account. It does not cover Logpush, Magic Transit, Magic WAN, Spectrum, Stream, Images, Turnstile or Waiting Room. + +## Setup + +You will need a Cloudflare **API token**. Legacy Global API Keys are not supported. + +1. Sign in to the [Cloudflare dashboard](https://dash.cloudflare.com). +2. Go to [**My Profile → API Tokens**](https://dash.cloudflare.com/profile/api-tokens) and click **Create Token**. +3. Scroll to the bottom and choose **Create Custom Token → Get started**. +4. Give the token a name, such as `SquaredUp`. +5. Under **Permissions**, add each row below. Every one is **Read** - the plugin never writes. Omit a row only if you do not use that product; the matching import step is optional and will report a warning rather than failing the import. + + | Scope | Permission | Access | + | ----------- | -------------------------------- | -------- | + | **Account** | Account Settings | **Read** | + | **Account** | Account Analytics | **Read** | + | **Account** | Workers Scripts | **Read** | + | **Account** | Workers R2 Storage | **Read** | + | **Account** | Workers KV Storage | **Read** | + | **Account** | D1 | **Read** | + | **Account** | Queues | **Read** | + | **Account** | Cloudflare Pages | **Read** | + | **Account** | Cloudflare Tunnel | **Read** | + | **Account** | Load Balancing: Monitors and Pools | **Read** | + | **Account** | Access: Apps and Policies | **Read** | + | **Zone** | Zone | **Read** | + | **Zone** | Zone Analytics | **Read** | + | **Zone** | DNS | **Read** | + | **Zone** | SSL and Certificates | **Read** | + | **Zone** | Health Checks | **Read** | + +6. Under **Account Resources**, choose **Include → All accounts** (or select the specific accounts you want SquaredUp to see). +7. Under **Zone Resources**, choose **Include → All zones from an account** or **All zones**. +8. Leave **Client IP Address Filtering** empty unless your SquaredUp agent has a fixed egress IP, and set **TTL** to a long expiry or leave it unset - an expired token stops all data collection. +9. Click **Continue to summary**, then **Create Token**, and copy the token shown. Cloudflare displays it **once only**. +10. Paste it into the **API token** field in SquaredUp. + +For more detail see Cloudflare's own guide to [creating API tokens](https://developers.cloudflare.com/fundamentals/api/get-started/create-token/). + +## Configuration fields + +| Field | What it is | Where to find it | Required | +| ------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | -------- | +| **API token** | A Cloudflare API token, sent as `Authorization: Bearer ` on every request to the API. | Cloudflare dashboard → [**My Profile → API Tokens**](https://dash.cloudflare.com/profile/api-tokens) → **Create Custom Token**. | Yes | + +On save, the plugin verifies the token against Cloudflare's token-verification endpoint. A failure means the token is invalid, expired or revoked - it does **not** check individual permissions, so a token that saves successfully can still return no data for a product whose permission you left out. + +## What this plugin monitors + +- **Zone traffic and caching** - requests, bandwidth, cached requests and bytes, page views, unique visitors and cache hit ratio per hour, plus breakdowns by country, status code, cache status, host, device type, HTTP protocol and content type. +- **Security** - firewall and WAF events by rule, service, country, host, user agent or path, with the action Cloudflare took; and SSL certificate inventory with days until expiry. +- **DNS and availability** - every DNS record in a zone with its type, content, TTL and proxy status; standalone health checks; and load balancer request distribution and per-origin pool health. +- **Developer platform** - Worker invocations, errors, subrequests and CPU-time percentiles; R2 bucket operations and stored size; KV operations, latency and stored keys; D1 query counts, rows touched and database size; Queue message operations and backlog; and Pages deployment history with branch and commit. +- **Zero Trust** - Access application inventory, Tunnel connector health, and daily Access login attempts by identity provider and country. + +The out-of-the-box dashboards include a **Cloudflare Overview** plus a perspective for each of the eleven indexed object types. + +## Data streams + +- **Zone Traffic** - hourly requests, bandwidth, cached traffic, threats, page views and cache hit ratio for a zone. +- **Zone Traffic Breakdown** - requests, bytes and visits for a zone grouped by a dimension you choose (country, status code, cache status, host, device type, HTTP protocol or content type). +- **Zone Firewall Events** - firewall and WAF event counts for a zone by action, grouped by rule, service, country, host, user agent or path. +- **Load Balancing Requests** - load balancer request counts for a zone by load balancer, pool, origin and edge location. +- **DNS Records** - every DNS record in a zone with type, content, TTL, proxy status and tags. +- **SSL Certificates** - certificate packs for a zone with issuer, validation method, expiry date and days until expiry. +- **Health Checks** - standalone health checks configured on a zone with status, address, interval and failure reason. +- **Worker Invocations** - requests, errors, subrequests and CPU-time percentiles for one Worker script. +- **R2 Operations** - requests and response bytes against an R2 bucket by operation type and outcome. +- **R2 Storage** - stored object count, payload size, metadata size and upload count for an R2 bucket over time. +- **KV Operations** - daily request counts and latency percentiles for a KV namespace by operation type. +- **KV Storage** - daily stored key count and byte size for a KV namespace. +- **D1 Queries** - daily read and write query counts, rows read and written, response bytes and query-time percentiles for a D1 database. +- **D1 Storage** - daily stored size of a D1 database. +- **Queue Message Operations** - message write, read and delete operations on a queue with outcome, consumer type, lag time and retry count. +- **Queue Backlog** - average messages and bytes waiting in a queue over time. +- **Pages Deployments** - deployment history for a Pages project with environment, status, branch, commit and URL. +- **Tunnel Connections** - active connector connections for a Tunnel with edge location, origin IP, connector version and architecture. +- **Load Balancer Pool Health** - per-origin health, response code, response time and failure reason for a pool at each Cloudflare edge location. +- **Access Logins** - daily Zero Trust login attempts for an Access application by identity provider, country and outcome. +- **GraphQL Query** - runs any query you write against Cloudflare's GraphQL Analytics API, for the many datasets this plugin has no dedicated stream for. + +Twelve further streams back the import and the setup check and are hidden from the tile editor. + +### Writing your own GraphQL queries + +Cloudflare's GraphQL Analytics API exposes far more datasets than this plugin ships streams for. The **GraphQL Query** stream is an escape hatch: paste a query, tell it where the rows live, and it shapes the result like any other stream. + +- `start` and `end` (ISO 8601) and `startDate` and `endDate` (`YYYY-MM-DD`) are supplied automatically from the tile's timeframe, so a query can filter with `datetime_geq: $start` or `date_geq: $startDate` without hardcoding dates. +- Anything you put in **Variables** is merged on top, which is how you supply an `accountTag` or `zoneTag` - the plugin config holds neither. +- **Path to data** points at the array of rows, e.g. `data.viewer.zones.0.httpRequests1hGroups`. Get it wrong and the error lists the array paths the response actually contains. +- Choose the **None** timeframe when your query hardcodes its own date filter. + +## What gets indexed + +| Object type | API source | Represents | +| ----------- | ---------- | ---------- | +| **Cloudflare Account** | `GET /accounts` | An account the API token can see. | +| **Cloudflare Zone** | `GET /zones` | A domain proxied through Cloudflare. | +| **Cloudflare Worker** | `GET /accounts/{id}/workers/scripts` | A deployed Worker script. | +| **Cloudflare R2 Bucket** | `GET /accounts/{id}/r2/buckets` | An R2 object storage bucket. | +| **Cloudflare Pages Project** | `GET /accounts/{id}/pages/projects` | A Cloudflare Pages project. | +| **Cloudflare D1 Database** | `GET /accounts/{id}/d1/database` | A D1 SQL database. | +| **Cloudflare KV Namespace** | `GET /accounts/{id}/storage/kv/namespaces` | A Workers KV namespace. | +| **Cloudflare Queue** | `GET /accounts/{id}/queues` | A Cloudflare Queue. | +| **Cloudflare Tunnel** | `GET /accounts/{id}/cfd_tunnel` | A `cloudflared` tunnel. | +| **Cloudflare Load Balancer Pool** | `GET /accounts/{id}/load_balancers/pools` | An origin pool used by load balancing. | +| **Cloudflare Access Application** | `GET /accounts/{id}/access/apps` | A Zero Trust Access application. | + +**Relationships:** every object except **Cloudflare Account** carries an `accountId` property identifying its owning account, and **Cloudflare Zone** additionally carries `accountName` and `planName`. These are stored as properties rather than graph links, so you can filter and group by account but the objects are not connected by edges. + +Worker and R2 Bucket identifiers are prefixed with the account id (`:`) because Cloudflare only guarantees those names are unique within an account. Every other type uses its own Cloudflare id. + +## Known limitations + +- **Analytics timeframes are capped per dataset, and the caps are short.** Cloudflare's GraphQL Analytics API limits how wide a single query's time range can be, and the limit differs for every dataset. These were measured against a Pro-plan account: + + | Data stream | Widest single query | Timeframes offered | + | ----------- | ------------------- | ------------------ | + | **Zone Traffic** | 3 days | Last 12 hours, Last 24 hours | + | **Zone Firewall Events** | 1 day | Last 12 hours, Last 24 hours | + | **Load Balancing Requests** | ~3 days | Last 12 hours, Last 24 hours | + | **Zone Traffic Breakdown** | 8 days | Last 12 hours, Last 24 hours, Last 7 days | + | **Access Logins** | 1 week | Last 7 days | + | **KV Operations / KV Storage** | ~32 days | Last 7 days, Last 30 days | + | **Worker Invocations**, **R2**, **D1**, **Queue** streams | 30 days or more | up to Last 30 days | + + Longer ranges are not offered because Cloudflare rejects them outright. Caps may differ on Free, Business and Enterprise plans. + +- **Daily-granularity datasets have no intraday view.** KV, D1 and Access analytics are aggregated by day, so their shortest timeframe is Last 7 days. +- **R2 must be activated before it returns anything.** If R2 has never been enabled in the Cloudflare dashboard, the import step for R2 buckets fails with *"Please enable R2 through the Cloudflare Dashboard"*. The step is optional, so the rest of the import still succeeds - but no R2 objects or metrics appear. +- **Zero Trust Access must be enabled** for the Access application import to work; otherwise Cloudflare returns *"Access is not enabled"*. +- **Load balancing analytics is gated per zone**, not per account. Zones without the Load Balancing add-on return an authorization error rather than empty data. +- **Pages endpoints cap page size at 10.** Cloudflare rejects any larger `per_page` on the Pages API, so Pages projects and deployments are fetched ten at a time. +- **Some resource lists are not paged.** R2 buckets, D1 databases, KV namespaces, Queues, Tunnels, load balancer pools and Access applications are imported in a single request each. If an account holds more of one of these than Cloudflare returns on one page, the remainder is not imported. +- **Rate limits.** The REST API allowed 1,200 requests per 300 seconds on the token tested, and Cloudflare documents a separate limit of 300 GraphQL queries per 5 minutes. Every analytics stream issues one request per selected object, so very large estates can hit these limits. +- **Hand-written GraphQL queries are unbounded.** The **GraphQL Query** stream runs whatever you give it, so it can hit limits the built-in streams are tuned to avoid: a large `limit` on a multi-dimension dataset can exceed the ~6 MB response cap, and a timeframe wider than that dataset's own cap fails outright. Prefer the pre-aggregated `*Groups` datasets over raw event datasets, and keep `limit` modest. The stream does not page, so your `limit` is the ceiling. +- **Imports run every 12 hours** by default, so newly created zones and resources are not visible immediately. +- **Read-only.** The plugin never creates, modifies or deletes anything in Cloudflare. diff --git a/plugins/Cloudflare/v1/icon.svg b/plugins/Cloudflare/v1/icon.svg new file mode 100644 index 00000000..f5cd685b --- /dev/null +++ b/plugins/Cloudflare/v1/icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/plugins/Cloudflare/v1/indexDefinitions/default.json b/plugins/Cloudflare/v1/indexDefinitions/default.json new file mode 100644 index 00000000..745664e0 --- /dev/null +++ b/plugins/Cloudflare/v1/indexDefinitions/default.json @@ -0,0 +1,468 @@ +{ + "steps": [ + { + "name": "accounts", + "dataStream": { + "name": "accounts" + }, + "timeframe": "none", + "objectMapping": { + "id": "id", + "name": "name", + "type": { + "value": "Cloudflare Account" + }, + "properties": [ + { + "accountType": "type" + }, + { + "createdOn": "created_on" + }, + { + "abuseContactEmail": "settings.abuse_contact_email" + }, + { + "enforceTwoFactor": "settings.enforce_twofactor" + } + ] + } + }, + { + "name": "zones", + "dataStream": { + "name": "zones" + }, + "timeframe": "none", + "objectMapping": { + "id": "id", + "name": "name", + "type": { + "value": "Cloudflare Zone" + }, + "properties": [ + "status", + "paused", + "accountId", + "accountName", + "planName", + "developmentModeActive", + { + "zoneType": "type" + }, + { + "createdOn": "created_on" + }, + { + "activatedOn": "activated_on" + }, + { + "nameServers": "name_servers" + }, + "healthState" + ] + } + }, + { + "name": "workerScripts", + "dataStream": { + "name": "workerScripts" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "scriptName", + "type": { + "value": "Cloudflare Worker" + }, + "properties": [ + "accountId", + "usageModel", + "handlers", + "placementMode", + "logpush", + "createdOn", + "modifiedOn" + ] + } + }, + { + "name": "r2Buckets", + "dataStream": { + "name": "r2Buckets" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "bucketName", + "type": { + "value": "Cloudflare R2 Bucket" + }, + "properties": [ + "accountId", + "location", + "storageClass", + "createdOn" + ] + } + }, + { + "name": "pagesProjects", + "dataStream": { + "name": "pagesProjects" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "projectName", + "type": { + "value": "Cloudflare Pages Project" + }, + "properties": [ + "accountId", + "subdomain", + "domains", + "productionBranch", + "latestDeploymentStatus", + "latestDeploymentOn", + "createdOn" + ] + } + }, + { + "name": "d1Databases", + "dataStream": { + "name": "d1Databases" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "databaseName", + "type": { + "value": "Cloudflare D1 Database" + }, + "properties": [ + "accountId", + "version", + "numTables", + "fileSize", + "createdOn" + ] + } + }, + { + "name": "kvNamespaces", + "dataStream": { + "name": "kvNamespaces" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "namespaceTitle", + "type": { + "value": "Cloudflare KV Namespace" + }, + "properties": [ + "accountId", + "supportsUrlEncoding" + ] + } + }, + { + "name": "queues", + "dataStream": { + "name": "queues" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "queueName", + "type": { + "value": "Cloudflare Queue" + }, + "properties": [ + "accountId", + "producers", + "consumers", + "createdOn", + "modifiedOn", + "consumerScripts" + ] + } + }, + { + "name": "tunnels", + "dataStream": { + "name": "tunnels" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "tunnelName", + "type": { + "value": "Cloudflare Tunnel" + }, + "properties": [ + "accountId", + "status", + "tunnelType", + "activeConnections", + "createdOn", + "healthState" + ] + } + }, + { + "name": "loadBalancerPools", + "dataStream": { + "name": "loadBalancerPools" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "poolName", + "type": { + "value": "Cloudflare Load Balancer Pool" + }, + "properties": [ + "accountId", + "enabled", + "originCount", + "minimumOrigins", + "monitorId", + "createdOn", + "modifiedOn" + ] + } + }, + { + "name": "accessApps", + "dataStream": { + "name": "accessApps" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "appName", + "type": { + "value": "Cloudflare Access Application" + }, + "properties": [ + "accountId", + "domain", + "appType", + "sessionDuration", + "appLauncherVisible", + "createdOn", + "modifiedOn" + ] + } + }, + { + "name": "durableObjectNamespaces", + "dataStream": { + "name": "durableObjectNamespaces" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "namespaceName", + "type": { + "value": "Cloudflare Durable Object Namespace" + }, + "properties": [ + "accountId", + "scriptName", + "className", + "usesSqlite" + ] + } + }, + { + "name": "vectorizeIndexes", + "dataStream": { + "name": "vectorizeIndexes" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "indexName", + "type": { + "value": "Cloudflare Vectorize Index" + }, + "properties": [ + "accountId", + "dimensions", + "metric", + "createdOn", + "modifiedOn" + ] + } + }, + { + "name": "hyperdriveConfigs", + "dataStream": { + "name": "hyperdriveConfigs" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "configName", + "type": { + "value": "Cloudflare Hyperdrive Config" + }, + "properties": [ + "accountId", + "database", + "host", + "scheme", + "cachingDisabled" + ] + } + }, + { + "name": "workerRoutes", + "dataStream": { + "name": "workerRoutes" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Zone\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "zones" + ], + "objectMapping": { + "id": "sourceId", + "name": "pattern", + "type": { + "value": "Cloudflare Worker Route" + }, + "properties": [ + "zoneId", + "zoneName", + "scriptName" + ] + } + }, + { + "name": "workerBindings", + "dataStream": { + "name": "workerBindings" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Worker\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "workerScripts" + ], + "objectMapping": { + "id": "sourceId", + "name": "bindingName", + "type": { + "value": "Cloudflare Worker Binding" + }, + "properties": [ + "bindingType", + "scriptName", + "accountId", + "kvNamespaceId", + "r2BucketName", + "d1DatabaseId", + "queueName", + "durableObjectNamespaceId", + "vectorizeIndexName", + "hyperdriveConfigId", + "serviceName" + ] + } + } + ] +} diff --git a/plugins/Cloudflare/v1/metadata.json b/plugins/Cloudflare/v1/metadata.json new file mode 100644 index 00000000..5ed67d31 --- /dev/null +++ b/plugins/Cloudflare/v1/metadata.json @@ -0,0 +1,83 @@ +{ + "name": "cloudflare", + "displayName": "Cloudflare", + "version": "1.1.0", + "author": { + "name": "@clarkd", + "type": "community" + }, + "description": "Monitor your Cloudflare account in SquaredUp - zone traffic, cache performance, firewall and WAF events, DNS records and SSL certificate expiry, plus Workers, R2, KV, D1, Queues, Pages, Tunnels, Load Balancers and Access applications.", + "category": "CDN", + "type": "hybrid", + "schemaVersion": "2.1", + "importNotSupported": false, + "restrictedToPlatforms": [], + "keywords": [ + "cloudflare", + "cdn", + "dns", + "waf", + "firewall", + "zones", + "workers", + "r2", + "kv", + "d1", + "queues", + "pages", + "tunnel", + "zero trust", + "access", + "load balancing", + "ssl", + "analytics", + "durable objects", + "vectorize", + "hyperdrive", + "ai" + ], + "objectTypes": [ + "Cloudflare Account", + "Cloudflare Zone", + "Cloudflare Worker", + "Cloudflare R2 Bucket", + "Cloudflare Pages Project", + "Cloudflare D1 Database", + "Cloudflare KV Namespace", + "Cloudflare Queue", + "Cloudflare Tunnel", + "Cloudflare Load Balancer Pool", + "Cloudflare Access Application", + "Cloudflare Durable Object Namespace", + "Cloudflare Vectorize Index", + "Cloudflare Hyperdrive Config", + "Cloudflare Worker Route", + "Cloudflare Worker Binding" + ], + "links": [ + { + "category": "documentation", + "url": "https://github.com/squaredup/plugins/blob/main/plugins/Cloudflare/v1/docs/README.md", + "label": "Help adding this plugin" + }, + { + "category": "source", + "url": "https://github.com/squaredup/plugins/tree/main/plugins/Cloudflare", + "label": "Repository" + } + ], + "base": { + "plugin": "WebAPI", + "majorVersion": "1", + "config": { + "baseUrl": "https://api.cloudflare.com/client/v4", + "authMode": "none", + "headers": [ + { + "key": "Authorization", + "value": "Bearer {{apiToken}}" + } + ] + } + } +} diff --git a/plugins/Cloudflare/v1/ui.json b/plugins/Cloudflare/v1/ui.json new file mode 100644 index 00000000..3698b831 --- /dev/null +++ b/plugins/Cloudflare/v1/ui.json @@ -0,0 +1,10 @@ +[ + { + "type": "password", + "name": "apiToken", + "label": "API token", + "placeholder": "Enter the Cloudflare API token", + "help": "Create a custom token at [My Profile → API Tokens](https://dash.cloudflare.com/profile/api-tokens) with **Read** access to the accounts, zones and products you want to monitor - the [setup guide](https://github.com/squaredup/plugins/blob/main/plugins/Cloudflare/v1/docs/README.md) lists the exact permissions. Legacy Global API Keys are not supported.", + "validation": { "required": true } + } +] From 2803790a8bb68aaa5a53cb83331f2b33b3dc1be3 Mon Sep 17 00:00:00 2001 From: Dave Clarke Date: Tue, 18 Aug 2026 15:37:24 +0100 Subject: [PATCH 02/27] Extending coverage & dashboards --- .../Cloudflare/v1/dataStreams/tunnels.json | 22 - plugins/Cloudflare/v1/dataStreams/zones.json | 22 - .../v1/defaultContent/account.dash.json | 863 +++++++++++++++++ .../durableObjectNamespace.dash.json | 574 +++++++++++ .../defaultContent/hyperdriveConfig.dash.json | 413 ++++++++ .../v1/defaultContent/manifest.json | 20 + .../v1/defaultContent/overview.dash.json | 476 ++++++++- .../Cloudflare/v1/defaultContent/scopes.json | 85 ++ .../defaultContent/vectorizeIndex.dash.json | 484 +++++++++ .../v1/defaultContent/workerBinding.dash.json | 63 ++ .../v1/defaultContent/workerRoute.dash.json | 63 ++ .../v1/defaultContent/zone.dash.json | 915 ++++++++++++++++++ plugins/Cloudflare/v1/docs/README.md | 53 +- .../v1/indexDefinitions/default.json | 6 +- 14 files changed, 3989 insertions(+), 70 deletions(-) create mode 100644 plugins/Cloudflare/v1/defaultContent/durableObjectNamespace.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/hyperdriveConfig.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/vectorizeIndex.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/workerBinding.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/workerRoute.dash.json diff --git a/plugins/Cloudflare/v1/dataStreams/tunnels.json b/plugins/Cloudflare/v1/dataStreams/tunnels.json index 83c0753c..4f50895c 100644 --- a/plugins/Cloudflare/v1/dataStreams/tunnels.json +++ b/plugins/Cloudflare/v1/dataStreams/tunnels.json @@ -108,28 +108,6 @@ "name": "createdOn", "displayName": "Created", "shape": "date" - }, - { - "name": "healthState", - "displayName": "Health", - "computed": true, - "valueExpression": "{{ $['status'] === 'healthy' ? 'success' : ((($['status'] === 'degraded') || ($['status'] === 'inactive')) ? 'warning' : 'error') }}", - "shape": [ - "state", - { - "map": { - "success": [ - "success" - ], - "warning": [ - "warning" - ], - "error": [ - "error" - ] - } - } - ] } ], "timeframes": false diff --git a/plugins/Cloudflare/v1/dataStreams/zones.json b/plugins/Cloudflare/v1/dataStreams/zones.json index 3cdf75c9..b1239fc5 100644 --- a/plugins/Cloudflare/v1/dataStreams/zones.json +++ b/plugins/Cloudflare/v1/dataStreams/zones.json @@ -152,28 +152,6 @@ "name": "name_servers", "displayName": "Name Servers", "shape": "string" - }, - { - "name": "healthState", - "displayName": "Health", - "computed": true, - "valueExpression": "{{ $['status'] === 'active' ? 'success' : ((($['status'] === 'pending') || ($['status'] === 'initializing')) ? 'warning' : 'error') }}", - "shape": [ - "state", - { - "map": { - "success": [ - "success" - ], - "warning": [ - "warning" - ], - "error": [ - "error" - ] - } - } - ] } ], "timeframes": false diff --git a/plugins/Cloudflare/v1/defaultContent/account.dash.json b/plugins/Cloudflare/v1/defaultContent/account.dash.json index 39b0634c..b26f672f 100644 --- a/plugins/Cloudflare/v1/defaultContent/account.dash.json +++ b/plugins/Cloudflare/v1/defaultContent/account.dash.json @@ -785,6 +785,869 @@ } } } + }, + { + "i": "d7931877-849c-421d-88e5-c5a83d107ce4", + "x": 0, + "y": 21, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[gatewayDnsQueries]}}", + "name": "gatewayDnsQueries", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "resolverDecision" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "queryCount" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "queryCount_sum", + "comparisonColumn": "none", + "label": "Gateway DNS Queries" + } + } + } + } + }, + { + "i": "6d0c0f83-1c51-43b7-90f1-1ec4226b8d2a", + "x": 1, + "y": 21, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[gatewayHttpRequests]}}", + "name": "gatewayHttpRequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "action" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "requests_sum", + "comparisonColumn": "none", + "label": "Gateway HTTP Requests" + } + } + } + } + }, + { + "i": "0e7ae631-b894-4f67-a73a-b9e61ce540f9", + "x": 2, + "y": 21, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workersAiInference]}}", + "name": "workersAiInference", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "modelId" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "requests_sum", + "comparisonColumn": "none", + "label": "AI Inference Requests" + } + } + } + } + }, + { + "i": "685debee-fe22-4057-be74-f16010314596", + "x": 3, + "y": 21, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workersAiInference]}}", + "name": "workersAiInference", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "modelId" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "outputTokens" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "outputTokens_sum", + "comparisonColumn": "none", + "label": "AI Output Tokens" + } + } + } + } + }, + { + "i": "2edd6feb-b28c-455a-bb9b-8abdbbf04638", + "x": 0, + "y": 23, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Gateway DNS Queries by Decision", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[gatewayDnsQueries]}}", + "name": "gatewayDnsQueries", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "resolverDecision" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "queryCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "queryCount_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "queryCount_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "fab0220c-a177-4a16-8d9b-a9bb5ebbd0fb", + "x": 2, + "y": 23, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Top Gateway DNS Categories", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[gatewayDnsQueries]}}", + "name": "gatewayDnsQueries", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "categoryNames" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "queryCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "queryCount_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "queryCount_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "daad39ca-4ae3-437e-a2a4-657f660e6045", + "x": 0, + "y": 26, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Gateway HTTP Requests by Action", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[gatewayHttpRequests]}}", + "name": "gatewayHttpRequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "action" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "requests_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "requests_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "7fe5da45-cb35-4c2b-98db-58e08a5bbbcd", + "x": 2, + "y": 26, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Top Gateway Hosts", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[gatewayHttpRequests]}}", + "name": "gatewayHttpRequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "httpHost" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "requests_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "requests_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "cb3540f5-b6f5-4596-9555-b9ee9a2b8792", + "x": 0, + "y": 29, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Gateway HTTP Requests Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[gatewayHttpRequests]}}", + "name": "gatewayHttpRequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "action" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "requests_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "6ebe2742-9444-4be7-9edc-1c5b1e113633", + "x": 2, + "y": 29, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Workers AI Requests by Model", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workersAiInference]}}", + "name": "workersAiInference", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "modelId" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "requests_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "requests_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "e3b25cc5-489a-4604-96ce-d49e3ee5b6e6", + "x": 0, + "y": 32, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Workers AI Token Usage", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workersAiInference]}}", + "name": "workersAiInference", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "modelId" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "inputTokens" + ] + }, + { + "type": "sum", + "names": [ + "outputTokens" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "inputTokens_sum", + "outputTokens_sum" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "2d7e5b1b-394e-4111-91de-2aa319f7fea8", + "x": 2, + "y": 32, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Workers AI Inference Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workersAiInference]}}", + "name": "workersAiInference", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "modelId" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "avgDurationMs" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "avgDurationMs_mean" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } } ] } diff --git a/plugins/Cloudflare/v1/defaultContent/durableObjectNamespace.dash.json b/plugins/Cloudflare/v1/defaultContent/durableObjectNamespace.dash.json new file mode 100644 index 00000000..d373680f --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/durableObjectNamespace.dash.json @@ -0,0 +1,574 @@ +{ + "name": "Durable Object Namespace", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": [ + "{{variables.[Cloudflare Durable Object Namespace]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "a786755f-c56a-4ca8-9fb2-39f56cd20e31", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[durableObjectInvocations]}}", + "name": "durableObjectInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Durable Object Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare Durable Object Namespace]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.requests_sum", + "comparisonColumn": "none", + "label": "Requests" + } + } + } + } + }, + { + "i": "cb4fcabf-dc89-4232-a781-9c19611252be", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[durableObjectInvocations]}}", + "name": "durableObjectInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.errors" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Durable Object Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare Durable Object Namespace]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.errors_sum", + "comparisonColumn": "none", + "label": "Errors" + } + } + } + } + }, + { + "i": "0d30e560-ae94-463d-9ded-b8fbdf5159f0", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[durableObjectInvocations]}}", + "name": "durableObjectInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "max", + "names": [ + "wallTimeP99Ms" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Durable Object Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare Durable Object Namespace]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "wallTimeP99Ms_max", + "comparisonColumn": "none", + "label": "Wall Time P99" + } + } + } + } + }, + { + "i": "d8b61347-3327-434c-afe1-9f8b50e171a9", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[durableObjectStorage]}}", + "name": "durableObjectStorage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "max", + "names": [ + "max.storedBytes" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Durable Object Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare Durable Object Namespace]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "max.storedBytes_max", + "comparisonColumn": "none", + "label": "Storage Size" + } + } + } + } + }, + { + "i": "922f325e-0310-4554-ba44-047abe041585", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Namespace Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Durable Object Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare Durable Object Namespace]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "b79735b7-97f5-41e6-9c78-3bd0ec38f2a9", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Requests and Errors", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[durableObjectInvocations]}}", + "name": "durableObjectInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetime", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + }, + { + "type": "sum", + "names": [ + "sum.errors" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.datetime_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Durable Object Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare Durable Object Namespace]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byDay", + "yAxisColumn": [ + "sum.requests_sum", + "sum.errors_sum" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "6cf4d972-b6ed-4483-a65c-d5321fb45b96", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Wall Time Percentiles", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[durableObjectInvocations]}}", + "name": "durableObjectInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetime", + "byDay" + ] + ], + "aggregate": [ + { + "type": "max", + "names": [ + "wallTimeP50Ms" + ] + }, + { + "type": "max", + "names": [ + "wallTimeP90Ms" + ] + }, + { + "type": "max", + "names": [ + "wallTimeP99Ms" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.datetime_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Durable Object Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare Durable Object Namespace]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byDay", + "yAxisColumn": [ + "wallTimeP50Ms_max", + "wallTimeP90Ms_max", + "wallTimeP99Ms_max" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "f332ae67-843b-4f3e-b11a-b4dee654faef", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Requests by Status", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[durableObjectInvocations]}}", + "name": "durableObjectInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.status", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "sum.requests_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Durable Object Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare Durable Object Namespace]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "sum.requests_sum", + "labelColumn": "dimensions.status_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "5f15f55e-adb8-448f-a49a-c2d3dd5c4a1d", + "x": 0, + "y": 8, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Storage Size", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[durableObjectStorage]}}", + "name": "durableObjectStorage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "max", + "names": [ + "max.storedBytes" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Durable Object Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare Durable Object Namespace]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "max.storedBytes_max" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/hyperdriveConfig.dash.json b/plugins/Cloudflare/v1/defaultContent/hyperdriveConfig.dash.json new file mode 100644 index 00000000..4c55ff62 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/hyperdriveConfig.dash.json @@ -0,0 +1,413 @@ +{ + "name": "Hyperdrive Config", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": [ + "{{variables.[Cloudflare Hyperdrive Config]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "41abb800-fee6-4faa-9896-fffc02cfdac6", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[hyperdriveQueries]}}", + "name": "hyperdriveQueries", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Hyperdrive Configs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Hyperdrive Config]}}" + }, + "variables": [ + "{{variables.[Cloudflare Hyperdrive Config]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count_sum", + "comparisonColumn": "none", + "label": "Queries" + } + } + } + } + }, + { + "i": "a9690778-5c87-4946-ac7b-ffcca1707b17", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[hyperdriveQueries]}}", + "name": "hyperdriveQueries", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "mean", + "names": [ + "avg.queryLatency" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Hyperdrive Configs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Hyperdrive Config]}}" + }, + "variables": [ + "{{variables.[Cloudflare Hyperdrive Config]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "avg.queryLatency_mean", + "comparisonColumn": "none", + "label": "Avg Query Latency" + } + } + } + } + }, + { + "i": "46f83434-ce36-406f-a6f6-11d043f9dfff", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[hyperdriveQueries]}}", + "name": "hyperdriveQueries", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "max", + "names": [ + "count" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Hyperdrive Configs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Hyperdrive Config]}}" + }, + "variables": [ + "{{variables.[Cloudflare Hyperdrive Config]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count_max", + "comparisonColumn": "none", + "label": "Peak Daily Queries" + } + } + } + } + }, + { + "i": "79f122cb-d720-4caf-bc5e-ab297c42b7e8", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[hyperdriveQueries]}}", + "name": "hyperdriveQueries", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "max", + "names": [ + "avg.queryLatency" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Hyperdrive Configs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Hyperdrive Config]}}" + }, + "variables": [ + "{{variables.[Cloudflare Hyperdrive Config]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "avg.queryLatency_max", + "comparisonColumn": "none", + "label": "Peak Query Latency" + } + } + } + } + }, + { + "i": "2ffb0aae-abd1-4d7d-b42b-048e3000c6d0", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Config Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Hyperdrive Configs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Hyperdrive Config]}}" + }, + "variables": [ + "{{variables.[Cloudflare Hyperdrive Config]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "6425b417-e265-4e0a-952e-2f44476bf920", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Queries", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[hyperdriveQueries]}}", + "name": "hyperdriveQueries", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Hyperdrive Configs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Hyperdrive Config]}}" + }, + "variables": [ + "{{variables.[Cloudflare Hyperdrive Config]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "count_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "d8a14720-8c85-4e12-bb86-8a7bd9952aaa", + "x": 0, + "y": 5, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Query Latency", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[hyperdriveQueries]}}", + "name": "hyperdriveQueries", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "avg.queryLatency" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Hyperdrive Configs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Hyperdrive Config]}}" + }, + "variables": [ + "{{variables.[Cloudflare Hyperdrive Config]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "avg.queryLatency_mean" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/manifest.json b/plugins/Cloudflare/v1/defaultContent/manifest.json index 74187074..f69a19ec 100644 --- a/plugins/Cloudflare/v1/defaultContent/manifest.json +++ b/plugins/Cloudflare/v1/defaultContent/manifest.json @@ -47,6 +47,26 @@ { "name": "accessApplication", "type": "dashboard" + }, + { + "name": "durableObjectNamespace", + "type": "dashboard" + }, + { + "name": "vectorizeIndex", + "type": "dashboard" + }, + { + "name": "hyperdriveConfig", + "type": "dashboard" + }, + { + "name": "workerRoute", + "type": "dashboard" + }, + { + "name": "workerBinding", + "type": "dashboard" } ] } diff --git a/plugins/Cloudflare/v1/defaultContent/overview.dash.json b/plugins/Cloudflare/v1/defaultContent/overview.dash.json index d95b0659..73de2193 100644 --- a/plugins/Cloudflare/v1/defaultContent/overview.dash.json +++ b/plugins/Cloudflare/v1/defaultContent/overview.dash.json @@ -487,9 +487,204 @@ } }, { - "i": "01071810-2460-4d6f-ac37-2d8c6c78ace3", + "i": "524486a8-32fa-4f78-b4a9-6b7ed041e4a0", "x": 0, "y": 6, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": { + "type": "count" + }, + "comparisonColumn": "none", + "label": "Durable Object Namespaces" + } + } + } + } + }, + { + "i": "35d98b3f-2655-4aba-a3cd-88a226b17f42", + "x": 1, + "y": 6, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Vectorize Indexes]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": { + "type": "count" + }, + "comparisonColumn": "none", + "label": "Vectorize Indexes" + } + } + } + } + }, + { + "i": "0c653b77-3432-441f-b96c-8c719c5373c4", + "x": 2, + "y": 6, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Hyperdrive Configs]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": { + "type": "count" + }, + "comparisonColumn": "none", + "label": "Hyperdrive Configs" + } + } + } + } + }, + { + "i": "826954c4-1d61-4f57-ac7c-534bd68bc919", + "x": 3, + "y": 6, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Worker Routes]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": { + "type": "count" + }, + "comparisonColumn": "none", + "label": "Worker Routes" + } + } + } + } + }, + { + "i": "35149d84-7770-41ca-984d-dfb3d25af0f7", + "x": 0, + "y": 8, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Worker Bindings]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": { + "type": "count" + }, + "comparisonColumn": "none", + "label": "Worker Bindings" + } + } + } + } + }, + { + "i": "01071810-2460-4d6f-ac37-2d8c6c78ace3", + "x": 0, + "y": 10, "w": 2, "h": 3, "moved": false, @@ -550,7 +745,7 @@ { "i": "06de4718-8250-4cc0-b864-1d9cc11c1394", "x": 2, - "y": 6, + "y": 10, "w": 2, "h": 3, "moved": false, @@ -611,7 +806,7 @@ { "i": "6b70dcfc-f6fe-4f22-a57c-7fa7fa23be9c", "x": 0, - "y": 9, + "y": 13, "w": 4, "h": 3, "moved": false, @@ -662,7 +857,7 @@ { "i": "2bbc6141-d374-41c7-93b1-3b3f7677c193", "x": 0, - "y": 12, + "y": 16, "w": 4, "h": 4, "moved": false, @@ -732,7 +927,7 @@ { "i": "5be40674-431e-465f-94fc-3b658438dc77", "x": 0, - "y": 16, + "y": 20, "w": 2, "h": 3, "moved": false, @@ -783,7 +978,7 @@ { "i": "f51e9fdc-9a9e-4272-b24d-9d5d11eac793", "x": 2, - "y": 16, + "y": 20, "w": 2, "h": 3, "moved": false, @@ -834,7 +1029,7 @@ { "i": "f2587bfd-deef-45ac-9501-1d66bf9c7734", "x": 0, - "y": 19, + "y": 23, "w": 2, "h": 3, "moved": false, @@ -885,7 +1080,7 @@ { "i": "af6eee0c-cfbf-43e1-a51c-53dca0e9a356", "x": 2, - "y": 19, + "y": 23, "w": 2, "h": 3, "moved": false, @@ -935,7 +1130,7 @@ { "i": "9beee6df-b954-4c3f-9c99-dd09a66a3f6a", "x": 0, - "y": 22, + "y": 26, "w": 2, "h": 3, "moved": false, @@ -986,7 +1181,7 @@ { "i": "c6e175b9-164a-4b14-a4a2-22312083c04f", "x": 2, - "y": 22, + "y": 26, "w": 2, "h": 3, "moved": false, @@ -1036,7 +1231,7 @@ { "i": "62ced3d6-e538-4573-af2c-24365a1d7b52", "x": 0, - "y": 25, + "y": 29, "w": 2, "h": 3, "moved": false, @@ -1086,7 +1281,7 @@ { "i": "4a7ce999-9bb4-48f9-890d-6d6dcb4d5e49", "x": 2, - "y": 25, + "y": 29, "w": 2, "h": 3, "moved": false, @@ -1136,7 +1331,7 @@ { "i": "0db6f61a-dc9f-499c-bd92-b863f2cc9eed", "x": 0, - "y": 28, + "y": 32, "w": 4, "h": 3, "moved": false, @@ -1183,6 +1378,261 @@ } } } + }, + { + "i": "2e3d6f85-4a2c-4429-b1cc-f1b1a7750964", + "x": 0, + "y": 35, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Durable Object Namespaces", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "scriptName", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "f8197c33-da9e-4c1f-91eb-03271dec641f", + "x": 2, + "y": 35, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Vectorize Indexes", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Vectorize Indexes]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "metric", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "6f46fa83-d107-4c9e-a103-bb10026a3f91", + "x": 0, + "y": 38, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Hyperdrive Configs", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Hyperdrive Configs]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "database", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "7c07b110-f283-4502-a0fc-9d8790815b9c", + "x": 2, + "y": 38, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Worker Routes", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Worker Routes]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "scriptName", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "2115654f-a854-4c27-8231-e3d8dc3cd77c", + "x": 0, + "y": 41, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Worker Bindings", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Worker Bindings]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "bindingType", + "linkColumn": "link", + "columns": 4, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } } ] } diff --git a/plugins/Cloudflare/v1/defaultContent/scopes.json b/plugins/Cloudflare/v1/defaultContent/scopes.json index 60f3ea56..ceefaab0 100644 --- a/plugins/Cloudflare/v1/defaultContent/scopes.json +++ b/plugins/Cloudflare/v1/defaultContent/scopes.json @@ -185,5 +185,90 @@ "default": "none", "type": "object" } + }, + { + "name": "Cloudflare Durable Object Namespaces", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Durable Object Namespace" + ] + } + }, + "variable": { + "name": "Cloudflare Durable Object Namespace", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare Vectorize Indexes", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Vectorize Index" + ] + } + }, + "variable": { + "name": "Cloudflare Vectorize Index", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare Hyperdrive Configs", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Hyperdrive Config" + ] + } + }, + "variable": { + "name": "Cloudflare Hyperdrive Config", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare Worker Routes", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Worker Route" + ] + } + }, + "variable": { + "name": "Cloudflare Worker Route", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare Worker Bindings", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Worker Binding" + ] + } + }, + "variable": { + "name": "Cloudflare Worker Binding", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } } ] diff --git a/plugins/Cloudflare/v1/defaultContent/vectorizeIndex.dash.json b/plugins/Cloudflare/v1/defaultContent/vectorizeIndex.dash.json new file mode 100644 index 00000000..61524abe --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/vectorizeIndex.dash.json @@ -0,0 +1,484 @@ +{ + "name": "Vectorize Index", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": [ + "{{variables.[Cloudflare Vectorize Index]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "758ee019-0ad4-4cbd-9c9e-3d63373bb102", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[vectorizeQueries]}}", + "name": "vectorizeQueries", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Vectorize Indexes]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Vectorize Index]}}" + }, + "variables": [ + "{{variables.[Cloudflare Vectorize Index]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count_sum", + "comparisonColumn": "none", + "label": "Queries" + } + } + } + } + }, + { + "i": "ca765fe6-5d33-483c-a478-00031af1eaa5", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[vectorizeQueries]}}", + "name": "vectorizeQueries", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "mean", + "names": [ + "avg.requestDurationMs" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Vectorize Indexes]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Vectorize Index]}}" + }, + "variables": [ + "{{variables.[Cloudflare Vectorize Index]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "avg.requestDurationMs_mean", + "comparisonColumn": "none", + "label": "Avg Query Latency" + } + } + } + } + }, + { + "i": "a3605dd6-c981-45c3-915b-52441a1a7f74", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[vectorizeStorage]}}", + "name": "vectorizeStorage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "max", + "names": [ + "max.vectorCount" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Vectorize Indexes]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Vectorize Index]}}" + }, + "variables": [ + "{{variables.[Cloudflare Vectorize Index]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "max.vectorCount_max", + "comparisonColumn": "none", + "label": "Stored Vectors" + } + } + } + } + }, + { + "i": "07770f5c-bc7b-4e78-9ea5-2f059c967680", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[vectorizeStorage]}}", + "name": "vectorizeStorage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "max", + "names": [ + "max.storedVectorDimensions" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Vectorize Indexes]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Vectorize Index]}}" + }, + "variables": [ + "{{variables.[Cloudflare Vectorize Index]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "max.storedVectorDimensions_max", + "comparisonColumn": "none", + "label": "Vector Dimensions" + } + } + } + } + }, + { + "i": "91c841e0-e59c-4142-883b-1bd3024c73be", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Index Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Vectorize Indexes]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Vectorize Index]}}" + }, + "variables": [ + "{{variables.[Cloudflare Vectorize Index]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "2807ff07-c2c8-4bc9-a73d-ee3b4db7eefd", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Queries", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[vectorizeQueries]}}", + "name": "vectorizeQueries", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Vectorize Indexes]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Vectorize Index]}}" + }, + "variables": [ + "{{variables.[Cloudflare Vectorize Index]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "count_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "80f34a72-0101-4f51-8c9b-adea02e01bd8", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Query Latency", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[vectorizeQueries]}}", + "name": "vectorizeQueries", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "avg.requestDurationMs" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Vectorize Indexes]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Vectorize Index]}}" + }, + "variables": [ + "{{variables.[Cloudflare Vectorize Index]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "avg.requestDurationMs_mean" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "01fd151e-a4ea-4f50-b458-5f4ab2c0cdfc", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Stored Vectors", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[vectorizeStorage]}}", + "name": "vectorizeStorage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "max", + "names": [ + "max.vectorCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Vectorize Indexes]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Vectorize Index]}}" + }, + "variables": [ + "{{variables.[Cloudflare Vectorize Index]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "max.vectorCount_max" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/workerBinding.dash.json b/plugins/Cloudflare/v1/defaultContent/workerBinding.dash.json new file mode 100644 index 00000000..4251bcfe --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/workerBinding.dash.json @@ -0,0 +1,63 @@ +{ + "name": "Worker Binding", + "schemaVersion": "1.5", + "timeframe": "none", + "variables": [ + "{{variables.[Cloudflare Worker Binding]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "ea9ba9d6-1b0b-45dd-9ea9-c9d2f3d49cdd", + "x": 0, + "y": 0, + "w": 4, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Binding Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Worker Bindings]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Worker Binding]}}" + }, + "variables": [ + "{{variables.[Cloudflare Worker Binding]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/workerRoute.dash.json b/plugins/Cloudflare/v1/defaultContent/workerRoute.dash.json new file mode 100644 index 00000000..681d388d --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/workerRoute.dash.json @@ -0,0 +1,63 @@ +{ + "name": "Worker Route", + "schemaVersion": "1.5", + "timeframe": "none", + "variables": [ + "{{variables.[Cloudflare Worker Route]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "04b5665c-896e-4623-9dcf-cc298dc3c6cb", + "x": 0, + "y": 0, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Route Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Worker Routes]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Worker Route]}}" + }, + "variables": [ + "{{variables.[Cloudflare Worker Route]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/zone.dash.json b/plugins/Cloudflare/v1/defaultContent/zone.dash.json index d09483d3..e4a27927 100644 --- a/plugins/Cloudflare/v1/defaultContent/zone.dash.json +++ b/plugins/Cloudflare/v1/defaultContent/zone.dash.json @@ -1337,6 +1337,921 @@ } } } + }, + { + "i": "99e46b39-b7fd-4d39-8990-7bfec62f4a92", + "x": 0, + "y": 31, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumWebVitals]}}", + "name": "rumWebVitals", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "mean", + "names": [ + "largestContentfulPaintP75" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "largestContentfulPaintP75_mean", + "comparisonColumn": "none", + "label": "LCP (P75)" + } + } + } + } + }, + { + "i": "5817c6a0-7759-4c3a-93a8-dfce7f44fc97", + "x": 1, + "y": 31, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumWebVitals]}}", + "name": "rumWebVitals", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "mean", + "names": [ + "interactionToNextPaintP75" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "interactionToNextPaintP75_mean", + "comparisonColumn": "none", + "label": "INP (P75)" + } + } + } + } + }, + { + "i": "3681fbe9-0fb2-449b-85c3-f66e81c37fe3", + "x": 2, + "y": 31, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumWebVitals]}}", + "name": "rumWebVitals", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "mean", + "names": [ + "cumulativeLayoutShiftP75" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "cumulativeLayoutShiftP75_mean", + "comparisonColumn": "none", + "label": "CLS (P75)" + } + } + } + } + }, + { + "i": "865ade66-66ea-441f-a6d0-27a3d8a7f26d", + "x": 3, + "y": 31, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumWebVitals]}}", + "name": "rumWebVitals", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count_sum", + "comparisonColumn": "none", + "label": "RUM Samples" + } + } + } + } + }, + { + "i": "0f48a7c9-fcf3-416a-b2f0-d6c2e5cabcc1", + "x": 0, + "y": 33, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Core Web Vitals Trend", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumWebVitals]}}", + "name": "rumWebVitals", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "largestContentfulPaintP75" + ] + }, + { + "type": "mean", + "names": [ + "interactionToNextPaintP75" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "largestContentfulPaintP75_mean", + "interactionToNextPaintP75_mean" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "1448aa66-c33d-42c8-b310-aab9100ef8a2", + "x": 2, + "y": 33, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Cumulative Layout Shift Trend", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumWebVitals]}}", + "name": "rumWebVitals", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "cumulativeLayoutShiftP75" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "cumulativeLayoutShiftP75_mean" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "3fa5456b-67bc-4f54-b2f7-9f20cad1aa50", + "x": 0, + "y": 36, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Page Views by Country", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumPageLoads]}}", + "name": "rumPageLoads", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "countryName" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "pageViews" + ] + } + ] + }, + "sort": { + "by": [ + [ + "pageViews_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "pageViews_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "b46fbd5f-b49c-40e6-9780-39fd9d287f6c", + "x": 2, + "y": 36, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Page Views by Device Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumPageLoads]}}", + "name": "rumPageLoads", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "deviceType" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "pageViews" + ] + } + ] + }, + "sort": { + "by": [ + [ + "pageViews_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "pageViews_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "736448a6-7b52-440a-b866-f2f4b23ab048", + "x": 0, + "y": 39, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Page Views and Visits", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumPageLoads]}}", + "name": "rumPageLoads", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "countryName" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "pageViews" + ] + }, + { + "type": "sum", + "names": [ + "visits" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "pageViews_sum", + "visits_sum" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "bba8874b-de16-4088-ba86-f7a3f1242e6e", + "x": 0, + "y": 42, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "DNS Queries by Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneDnsAnalytics]}}", + "name": "zoneDnsAnalytics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "queryType" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "queryCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "queryCount_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "queryCount_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "c8c8b28e-1fed-4543-87d6-821ef74a884b", + "x": 2, + "y": 42, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "DNS Response Codes", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneDnsAnalytics]}}", + "name": "zoneDnsAnalytics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "responseCode" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "queryCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "queryCount_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "queryCount_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "bb2d2cdd-d041-435a-b77f-47ef0f8190b8", + "x": 0, + "y": 45, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "DNS Queries Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneDnsAnalytics]}}", + "name": "zoneDnsAnalytics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "queryType" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "queryCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "queryCount_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "78551a25-ceca-4256-9111-1e195d3afa3b", + "x": 2, + "y": 45, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "DNS Response Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneDnsAnalytics]}}", + "name": "zoneDnsAnalytics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "queryType" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "avgResponseTimeMs" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "avgResponseTimeMs_mean" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } } ] } diff --git a/plugins/Cloudflare/v1/docs/README.md b/plugins/Cloudflare/v1/docs/README.md index 5a0830c1..f59004a2 100644 --- a/plugins/Cloudflare/v1/docs/README.md +++ b/plugins/Cloudflare/v1/docs/README.md @@ -31,6 +31,8 @@ You will need a Cloudflare **API token**. Legacy Global API Keys are not support | **Zone** | SSL and Certificates | **Read** | | **Zone** | Health Checks | **Read** | + The Durable Objects, Vectorize and Hyperdrive endpoints were reachable in testing with the permissions above and needed nothing extra. If your account restricts those products and their imports come back empty, add their **Read** permissions too. The Zero Trust Gateway streams read through **Account Analytics**, so they need no separate Gateway permission. + 6. Under **Account Resources**, choose **Include → All accounts** (or select the specific accounts you want SquaredUp to see). 7. Under **Zone Resources**, choose **Include → All zones from an account** or **All zones**. 8. Leave **Client IP Address Filtering** empty unless your SquaredUp agent has a fixed egress IP, and set **TTL** to a long expiry or leave it unset - an expired token stops all data collection. @@ -52,10 +54,12 @@ On save, the plugin verifies the token against Cloudflare's token-verification e - **Zone traffic and caching** - requests, bandwidth, cached requests and bytes, page views, unique visitors and cache hit ratio per hour, plus breakdowns by country, status code, cache status, host, device type, HTTP protocol and content type. - **Security** - firewall and WAF events by rule, service, country, host, user agent or path, with the action Cloudflare took; and SSL certificate inventory with days until expiry. - **DNS and availability** - every DNS record in a zone with its type, content, TTL and proxy status; standalone health checks; and load balancer request distribution and per-origin pool health. -- **Developer platform** - Worker invocations, errors, subrequests and CPU-time percentiles; R2 bucket operations and stored size; KV operations, latency and stored keys; D1 query counts, rows touched and database size; Queue message operations and backlog; and Pages deployment history with branch and commit. -- **Zero Trust** - Access application inventory, Tunnel connector health, and daily Access login attempts by identity provider and country. +- **Web performance** - Core Web Vitals (Largest Contentful Paint, Interaction to Next Paint, Cumulative Layout Shift) and page-load volume from Cloudflare Web Analytics, per zone. +- **Developer platform** - Worker invocations, errors, subrequests and CPU-time percentiles; R2 bucket operations and stored size; KV operations, latency and stored keys; D1 query counts, rows touched and database size; Queue message operations and backlog; Durable Object invocations and storage; Vectorize and Hyperdrive query volume; Workers AI inference by model; and Pages deployment history with branch and commit. +- **Dependency mapping** - which Worker binds which KV namespace, R2 bucket, D1 database, queue, Durable Object namespace, Vectorize index or Hyperdrive config, and which zones each Worker serves. +- **Zero Trust** - Access application inventory and login attempts, Tunnel connector health, and Gateway DNS and HTTP filtering activity. -The out-of-the-box dashboards include a **Cloudflare Overview** plus a perspective for each of the eleven indexed object types. +The out-of-the-box dashboards include a **Cloudflare Overview** plus a perspective for each indexed object type. ## Data streams @@ -79,9 +83,20 @@ The out-of-the-box dashboards include a **Cloudflare Overview** plus a perspecti - **Tunnel Connections** - active connector connections for a Tunnel with edge location, origin IP, connector version and architecture. - **Load Balancer Pool Health** - per-origin health, response code, response time and failure reason for a pool at each Cloudflare edge location. - **Access Logins** - daily Zero Trust login attempts for an Access application by identity provider, country and outcome. +- **DNS Analytics** - authoritative DNS query volume and response time for a zone, grouped by query name, query type, response code or edge location. +- **Web Analytics Page Loads** - page views and visits for a zone's hostnames, grouped by country, device type or referrer. +- **Core Web Vitals** - P75 Largest Contentful Paint, Interaction to Next Paint and Cumulative Layout Shift for a zone's hostnames. +- **Gateway DNS Queries** - Zero Trust Gateway DNS resolutions for an account by policy decision, category, location or query type. +- **Gateway HTTP Requests** - Zero Trust Gateway proxied web requests for an account by action, host or category. +- **Workers AI Inference** - Workers AI inference requests for an account by model, with token counts and average duration. +- **Durable Object Invocations** - requests, errors and wall-time percentiles for a Durable Object namespace. +- **Durable Object Storage** - stored bytes for a SQLite-backed Durable Object namespace over time. +- **Vectorize Queries** - query volume and average latency for a Vectorize index. +- **Vectorize Storage** - stored vector count and dimensions for a Vectorize index. +- **Hyperdrive Queries** - query volume and average latency for a Hyperdrive configuration. - **GraphQL Query** - runs any query you write against Cloudflare's GraphQL Analytics API, for the many datasets this plugin has no dedicated stream for. -Twelve further streams back the import and the setup check and are hidden from the tile editor. +Seventeen further streams back the import and the setup check and are hidden from the tile editor. ### Writing your own GraphQL queries @@ -107,10 +122,25 @@ Cloudflare's GraphQL Analytics API exposes far more datasets than this plugin sh | **Cloudflare Tunnel** | `GET /accounts/{id}/cfd_tunnel` | A `cloudflared` tunnel. | | **Cloudflare Load Balancer Pool** | `GET /accounts/{id}/load_balancers/pools` | An origin pool used by load balancing. | | **Cloudflare Access Application** | `GET /accounts/{id}/access/apps` | A Zero Trust Access application. | +| **Cloudflare Durable Object Namespace** | `GET /accounts/{id}/workers/durable_objects/namespaces` | A Durable Object namespace and the Worker class backing it. | +| **Cloudflare Vectorize Index** | `GET /accounts/{id}/vectorize/v2/indexes` | A Vectorize vector database index. | +| **Cloudflare Hyperdrive Config** | `GET /accounts/{id}/hyperdrive/configs` | A Hyperdrive database connection configuration. | +| **Cloudflare Worker Route** | `GET /zones/{id}/workers/routes` | A URL pattern routing a zone's requests to a Worker. | +| **Cloudflare Worker Binding** | `GET /accounts/{id}/workers/scripts/{name}/settings` | A resource bound to a Worker, such as a KV namespace or R2 bucket. | + +**Relationships:** the plugin ships correlation rules that draw edges between imported objects: + +| Relationship | How it matches | +| ------------ | -------------- | +| Every resource **belongs to** its Account | the resource's `accountId` against the account's id | +| Worker Binding **declared by** Worker, and **targets** the KV namespace / R2 bucket / D1 database / queue / Durable Object namespace / Vectorize index / Hyperdrive config it points at | the binding's target id against that resource's id | +| Worker **serves** Zone | through the Worker Route that names both | +| Pages Project **served by** Zone | the project's custom domains against the zone name | +| Queue **consumed by** Worker | the queue's consumer script names against the Worker name | -**Relationships:** every object except **Cloudflare Account** carries an `accountId` property identifying its owning account, and **Cloudflare Zone** additionally carries `accountName` and `planName`. These are stored as properties rather than graph links, so you can filter and group by account but the objects are not connected by edges. +Together these give a dependency graph: from a KV namespace you can see which Workers bind it, and from a Worker which zones it serves. -Worker and R2 Bucket identifiers are prefixed with the account id (`:`) because Cloudflare only guarantees those names are unique within an account. Every other type uses its own Cloudflare id. +Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed with the account id (`:`) because Cloudflare only guarantees those names are unique within an account. Every other type uses its own Cloudflare id. ## Known limitations @@ -122,8 +152,10 @@ Worker and R2 Bucket identifiers are prefixed with the account id (`: | **Zone Firewall Events** | 1 day | Last 12 hours, Last 24 hours | | **Load Balancing Requests** | ~3 days | Last 12 hours, Last 24 hours | | **Zone Traffic Breakdown** | 8 days | Last 12 hours, Last 24 hours, Last 7 days | - | **Access Logins** | 1 week | Last 7 days | - | **KV Operations / KV Storage** | ~32 days | Last 7 days, Last 30 days | + | **Access Logins**, **DNS Analytics** | 1 week | up to Last 7 days | + | **Gateway DNS Queries**, **Gateway HTTP Requests** | ~30 days | up to Last 30 days | + | **KV**, **Workers AI**, **Durable Object**, **Vectorize**, **Hyperdrive** streams | ~32 days | up to Last 30 days | + | **Web Analytics Page Loads**, **Core Web Vitals** | ~93 days | up to Last 30 days | | **Worker Invocations**, **R2**, **D1**, **Queue** streams | 30 days or more | up to Last 30 days | Longer ranges are not offered because Cloudflare rejects them outright. Caps may differ on Free, Business and Enterprise plans. @@ -131,9 +163,12 @@ Worker and R2 Bucket identifiers are prefixed with the account id (`: - **Daily-granularity datasets have no intraday view.** KV, D1 and Access analytics are aggregated by day, so their shortest timeframe is Last 7 days. - **R2 must be activated before it returns anything.** If R2 has never been enabled in the Cloudflare dashboard, the import step for R2 buckets fails with *"Please enable R2 through the Cloudflare Dashboard"*. The step is optional, so the rest of the import still succeeds - but no R2 objects or metrics appear. - **Zero Trust Access must be enabled** for the Access application import to work; otherwise Cloudflare returns *"Access is not enabled"*. +- **Web Analytics must be enabled per zone.** The RUM datasets are account-scoped and filtered to a zone by hostname, so a zone without the Web Analytics beacon installed returns nothing even though the query succeeds. Traffic from hosts that are not Cloudflare zones is not reachable from a zone-scoped tile. +- **Zero Trust Gateway must be configured** for the Gateway streams to return anything. The datasets are reachable without a Gateway subscription, so an empty result means no proxied traffic rather than a permissions problem. +- **Durable Object storage covers SQLite-backed namespaces only.** Cloudflare's account-wide storage dataset cannot be filtered per namespace, so the plugin uses the SQLite storage dataset, which can. Key-value-backed namespaces report no storage. - **Load balancing analytics is gated per zone**, not per account. Zones without the Load Balancing add-on return an authorization error rather than empty data. - **Pages endpoints cap page size at 10.** Cloudflare rejects any larger `per_page` on the Pages API, so Pages projects and deployments are fetched ten at a time. -- **Some resource lists are not paged.** R2 buckets, D1 databases, KV namespaces, Queues, Tunnels, load balancer pools and Access applications are imported in a single request each. If an account holds more of one of these than Cloudflare returns on one page, the remainder is not imported. +- **Some resource lists are not paged.** R2 buckets, D1 databases, Queues, load balancer pools, Access applications, Vectorize indexes, Hyperdrive configs, Worker scripts and Worker routes are imported in a single request each. Where Cloudflare's paging behaviour could be proven against real data it is used (zones, accounts, DNS records, Pages projects, KV namespaces, Tunnels and Durable Object namespaces all page); the rest were left unpaged because the endpoint either ignores the paging parameters outright — as `workers/scripts` does — or holds too few records in the tested account to confirm they are honoured. If an account holds more of one of these than Cloudflare returns on a single page, the remainder is not imported. - **Rate limits.** The REST API allowed 1,200 requests per 300 seconds on the token tested, and Cloudflare documents a separate limit of 300 GraphQL queries per 5 minutes. Every analytics stream issues one request per selected object, so very large estates can hit these limits. - **Hand-written GraphQL queries are unbounded.** The **GraphQL Query** stream runs whatever you give it, so it can hit limits the built-in streams are tuned to avoid: a large `limit` on a multi-dimension dataset can exceed the ~6 MB response cap, and a timeframe wider than that dataset's own cap fails outright. Prefer the pre-aggregated `*Groups` datasets over raw event datasets, and keep `limit` modest. The stream does not page, so your `limit` is the ceiling. - **Imports run every 12 hours** by default, so newly created zones and resources are not visible immediately. diff --git a/plugins/Cloudflare/v1/indexDefinitions/default.json b/plugins/Cloudflare/v1/indexDefinitions/default.json index 745664e0..6a369d24 100644 --- a/plugins/Cloudflare/v1/indexDefinitions/default.json +++ b/plugins/Cloudflare/v1/indexDefinitions/default.json @@ -58,8 +58,7 @@ }, { "nameServers": "name_servers" - }, - "healthState" + } ] } }, @@ -256,8 +255,7 @@ "status", "tunnelType", "activeConnections", - "createdOn", - "healthState" + "createdOn" ] } }, From 3950597d1f6035af8c4f67efef31453d462868eb Mon Sep 17 00:00:00 2001 From: Dave Clarke Date: Tue, 18 Aug 2026 22:11:18 +0100 Subject: [PATCH 03/27] Expand Cloudflare coverage: AI, Media, security and platform analytics Extends the plugin from 50 to 83 data streams and 16 to 23 object types, covering the product families that were previously missing entirely. New object types: Stream Video, Turnstile Widget, AI Gateway, AutoRAG, Container Application, Pipeline, Realtime App. New analytics: AI Gateway requests/errors/cache, AutoRAG queries, Browser Rendering, Stream minutes viewed and playback quality, Images requests and transformations, Realtime bandwidth, Turnstile challenges, Email Routing, DMARC, Cache Reserve operations and storage, Health Check events, Page Shield, Network Error Logs, DNS Firewall, Gateway network sessions, audit logs, Pages Functions, Queue consumer metrics, Durable Object subrequests and D1 query insights. Dashboards are regrouped into Cloudflare product-family folders (Core, Compute, Storage & Databases, AI, Media, Zero Trust, Traffic) rather than a flat list of 22. Notable fixes: - Pages Functions was scoped per project, but Cloudflare exposes only an internal script name with no mapping to the project, so it returned nothing despite real data existing. Now account-scoped with the function as a column. - Images transformations used a node that returns INTERNAL_SERVER_ERROR for every query; moved to imagesUniqueTransformations, which responds. - errorHandling never fires for Cloudflare's HTTP-200-with-errors responses, so all 22 scripted GraphQL streams now raise the error themselves rather than shaping it into an empty result. - Cost is reported as a plain number: Cloudflare states no currency. - Restored two scopes referenced by Overview tiles but missing from scopes.json. Every query was verified against the live GraphQL schema by introspection, and each node's time-range cap measured rather than assumed. Many streams return no data in the test account because the product is not provisioned; docs/README.md records which, and why. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01CXgffao5bcMhNz3Ci7eCi9 --- .../relate-resources-to-account.json | 9 +- plugins/Cloudflare/v1/custom_types.json | 49 + .../v1/dataStreams/aiGatewayCache.json | 57 + .../v1/dataStreams/aiGatewayErrors.json | 71 + .../v1/dataStreams/aiGatewayRequests.json | 146 ++ .../Cloudflare/v1/dataStreams/aiGateways.json | 75 + .../Cloudflare/v1/dataStreams/auditLogs.json | 77 + .../v1/dataStreams/autoragInstances.json | 70 + .../v1/dataStreams/autoragQueries.json | 83 + .../v1/dataStreams/browserRendering.json | 93 ++ .../dataStreams/cacheReserveOperations.json | 62 + .../v1/dataStreams/cacheReserveStorage.json | 50 + .../v1/dataStreams/containerApps.json | 75 + .../v1/dataStreams/containerMetrics.json | 93 ++ .../Cloudflare/v1/dataStreams/d1Queries.json | 94 ++ .../v1/dataStreams/dmarcReports.json | 69 + .../v1/dataStreams/dnsFirewallAnalytics.json | 69 + .../dataStreams/durableObjectSubrequests.json | 59 + .../v1/dataStreams/emailRouting.json | 64 + .../dataStreams/gatewayNetworkSessions.json | 66 + .../v1/dataStreams/imagesRequests.json | 44 + .../v1/dataStreams/imagesTransformations.json | 44 + .../pagesFunctionsInvocations.json | 78 + .../v1/dataStreams/pipelineIngestion.json | 59 + .../Cloudflare/v1/dataStreams/pipelines.json | 65 + .../v1/dataStreams/queueConsumerMetrics.json | 59 + .../v1/dataStreams/realtimeApps.json | 65 + .../v1/dataStreams/realtimeUsage.json | 60 + .../v1/dataStreams/scripts/aiGateways.js | 17 + .../v1/dataStreams/scripts/auditLogs.js | 34 + .../dataStreams/scripts/autoragInstances.js | 13 + .../dataStreams/scripts/browserRendering.js | 49 + .../scripts/cacheReserveOperations.js | 34 + .../v1/dataStreams/scripts/containerApps.js | 17 + .../dataStreams/scripts/containerMetrics.js | 42 + .../v1/dataStreams/scripts/dmarcReports.js | 35 + .../scripts/dnsFirewallAnalytics.js | 48 + .../v1/dataStreams/scripts/emailRouting.js | 34 + .../dataStreams/scripts/gatewayDnsQueries.js | 7 + .../scripts/gatewayHttpRequests.js | 7 + .../scripts/gatewayNetworkSessions.js | 39 + .../v1/dataStreams/scripts/imagesRequests.js | 27 + .../scripts/imagesTransformations.js | 20 + .../v1/dataStreams/scripts/pipelines.js | 12 + .../v1/dataStreams/scripts/realtimeApps.js | 12 + .../v1/dataStreams/scripts/rumPageLoads.js | 7 + .../v1/dataStreams/scripts/streamCmcd.js | 38 + .../v1/dataStreams/scripts/streamVideos.js | 21 + .../scripts/turnstileChallenges.js | 39 + .../dataStreams/scripts/turnstileWidgets.js | 16 + .../dataStreams/scripts/workersAiInference.js | 7 + .../dataStreams/scripts/zoneDnsAnalytics.js | 7 + .../dataStreams/scripts/zoneFirewallEvents.js | 7 + .../v1/dataStreams/scripts/zoneNelReports.js | 46 + .../v1/dataStreams/scripts/zonePageShield.js | 46 + .../scripts/zoneTrafficBreakdown.js | 7 + .../Cloudflare/v1/dataStreams/streamCmcd.json | 83 + .../v1/dataStreams/streamMinutesViewed.json | 49 + .../v1/dataStreams/streamVideos.json | 90 + .../v1/dataStreams/turnstileChallenges.json | 63 + .../v1/dataStreams/turnstileWidgets.json | 85 + .../v1/dataStreams/zoneHealthCheckEvents.json | 87 + .../v1/dataStreams/zoneNelReports.json | 64 + .../v1/dataStreams/zonePageShield.json | 64 + .../v1/defaultContent/AI/aiGateway.dash.json | 830 ++++++++++ .../v1/defaultContent/AI/autorag.dash.json | 595 +++++++ .../v1/defaultContent/AI/manifest.json | 16 + .../{ => AI}/vectorizeIndex.dash.json | 0 .../Compute/containerApplication.dash.json | 669 ++++++++ .../durableObjectNamespace.dash.json | 71 + .../v1/defaultContent/Compute/manifest.json | 28 + .../{ => Compute}/pagesProject.dash.json | 0 .../defaultContent/Compute/pipeline.dash.json | 484 ++++++ .../{ => Compute}/queue.dash.json | 71 + .../{ => Compute}/worker.dash.json | 0 .../{ => Core}/account.dash.json | 1472 ++++++++++++++++- .../v1/defaultContent/Core/manifest.json | 12 + .../defaultContent/{ => Core}/zone.dash.json | 748 +++++++++ .../v1/defaultContent/Media/manifest.json | 12 + .../Media/realtimeApp.dash.json | 500 ++++++ .../Media/streamVideo.dash.json | 668 ++++++++ .../d1Database.dash.json | 139 ++ .../hyperdriveConfig.dash.json | 0 .../kvNamespace.dash.json | 0 .../Storage & Databases/manifest.json | 20 + .../r2Bucket.dash.json | 0 .../{ => Traffic}/loadBalancerPool.dash.json | 0 .../v1/defaultContent/Traffic/manifest.json | 8 + .../accessApplication.dash.json | 0 .../defaultContent/Zero Trust/manifest.json | 16 + .../{ => Zero Trust}/tunnel.dash.json | 0 .../Zero Trust/turnstileWidget.dash.json | 514 ++++++ .../v1/defaultContent/manifest.json | 64 +- .../v1/defaultContent/overview.dash.json | 355 ++++ .../Cloudflare/v1/defaultContent/scopes.json | 119 ++ .../v1/defaultContent/workerBinding.dash.json | 63 - .../v1/defaultContent/workerRoute.dash.json | 63 - plugins/Cloudflare/v1/docs/README.md | 72 +- .../v1/indexDefinitions/default.json | 195 +++ plugins/Cloudflare/v1/metadata.json | 21 +- 100 files changed, 10721 insertions(+), 282 deletions(-) create mode 100644 plugins/Cloudflare/v1/dataStreams/aiGatewayCache.json create mode 100644 plugins/Cloudflare/v1/dataStreams/aiGatewayErrors.json create mode 100644 plugins/Cloudflare/v1/dataStreams/aiGatewayRequests.json create mode 100644 plugins/Cloudflare/v1/dataStreams/aiGateways.json create mode 100644 plugins/Cloudflare/v1/dataStreams/auditLogs.json create mode 100644 plugins/Cloudflare/v1/dataStreams/autoragInstances.json create mode 100644 plugins/Cloudflare/v1/dataStreams/autoragQueries.json create mode 100644 plugins/Cloudflare/v1/dataStreams/browserRendering.json create mode 100644 plugins/Cloudflare/v1/dataStreams/cacheReserveOperations.json create mode 100644 plugins/Cloudflare/v1/dataStreams/cacheReserveStorage.json create mode 100644 plugins/Cloudflare/v1/dataStreams/containerApps.json create mode 100644 plugins/Cloudflare/v1/dataStreams/containerMetrics.json create mode 100644 plugins/Cloudflare/v1/dataStreams/d1Queries.json create mode 100644 plugins/Cloudflare/v1/dataStreams/dmarcReports.json create mode 100644 plugins/Cloudflare/v1/dataStreams/dnsFirewallAnalytics.json create mode 100644 plugins/Cloudflare/v1/dataStreams/durableObjectSubrequests.json create mode 100644 plugins/Cloudflare/v1/dataStreams/emailRouting.json create mode 100644 plugins/Cloudflare/v1/dataStreams/gatewayNetworkSessions.json create mode 100644 plugins/Cloudflare/v1/dataStreams/imagesRequests.json create mode 100644 plugins/Cloudflare/v1/dataStreams/imagesTransformations.json create mode 100644 plugins/Cloudflare/v1/dataStreams/pagesFunctionsInvocations.json create mode 100644 plugins/Cloudflare/v1/dataStreams/pipelineIngestion.json create mode 100644 plugins/Cloudflare/v1/dataStreams/pipelines.json create mode 100644 plugins/Cloudflare/v1/dataStreams/queueConsumerMetrics.json create mode 100644 plugins/Cloudflare/v1/dataStreams/realtimeApps.json create mode 100644 plugins/Cloudflare/v1/dataStreams/realtimeUsage.json create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/aiGateways.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/auditLogs.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/autoragInstances.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/browserRendering.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/cacheReserveOperations.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/containerApps.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/containerMetrics.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/dmarcReports.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/dnsFirewallAnalytics.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/emailRouting.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/gatewayNetworkSessions.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/imagesRequests.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/imagesTransformations.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/pipelines.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/realtimeApps.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/streamCmcd.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/streamVideos.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/turnstileChallenges.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/turnstileWidgets.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/zoneNelReports.js create mode 100644 plugins/Cloudflare/v1/dataStreams/scripts/zonePageShield.js create mode 100644 plugins/Cloudflare/v1/dataStreams/streamCmcd.json create mode 100644 plugins/Cloudflare/v1/dataStreams/streamMinutesViewed.json create mode 100644 plugins/Cloudflare/v1/dataStreams/streamVideos.json create mode 100644 plugins/Cloudflare/v1/dataStreams/turnstileChallenges.json create mode 100644 plugins/Cloudflare/v1/dataStreams/turnstileWidgets.json create mode 100644 plugins/Cloudflare/v1/dataStreams/zoneHealthCheckEvents.json create mode 100644 plugins/Cloudflare/v1/dataStreams/zoneNelReports.json create mode 100644 plugins/Cloudflare/v1/dataStreams/zonePageShield.json create mode 100644 plugins/Cloudflare/v1/defaultContent/AI/aiGateway.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/AI/autorag.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/AI/manifest.json rename plugins/Cloudflare/v1/defaultContent/{ => AI}/vectorizeIndex.dash.json (100%) create mode 100644 plugins/Cloudflare/v1/defaultContent/Compute/containerApplication.dash.json rename plugins/Cloudflare/v1/defaultContent/{ => Compute}/durableObjectNamespace.dash.json (88%) create mode 100644 plugins/Cloudflare/v1/defaultContent/Compute/manifest.json rename plugins/Cloudflare/v1/defaultContent/{ => Compute}/pagesProject.dash.json (100%) create mode 100644 plugins/Cloudflare/v1/defaultContent/Compute/pipeline.dash.json rename plugins/Cloudflare/v1/defaultContent/{ => Compute}/queue.dash.json (88%) rename plugins/Cloudflare/v1/defaultContent/{ => Compute}/worker.dash.json (100%) rename plugins/Cloudflare/v1/defaultContent/{ => Core}/account.dash.json (55%) create mode 100644 plugins/Cloudflare/v1/defaultContent/Core/manifest.json rename plugins/Cloudflare/v1/defaultContent/{ => Core}/zone.dash.json (74%) create mode 100644 plugins/Cloudflare/v1/defaultContent/Media/manifest.json create mode 100644 plugins/Cloudflare/v1/defaultContent/Media/realtimeApp.dash.json create mode 100644 plugins/Cloudflare/v1/defaultContent/Media/streamVideo.dash.json rename plugins/Cloudflare/v1/defaultContent/{ => Storage & Databases}/d1Database.dash.json (80%) rename plugins/Cloudflare/v1/defaultContent/{ => Storage & Databases}/hyperdriveConfig.dash.json (100%) rename plugins/Cloudflare/v1/defaultContent/{ => Storage & Databases}/kvNamespace.dash.json (100%) create mode 100644 plugins/Cloudflare/v1/defaultContent/Storage & Databases/manifest.json rename plugins/Cloudflare/v1/defaultContent/{ => Storage & Databases}/r2Bucket.dash.json (100%) rename plugins/Cloudflare/v1/defaultContent/{ => Traffic}/loadBalancerPool.dash.json (100%) create mode 100644 plugins/Cloudflare/v1/defaultContent/Traffic/manifest.json rename plugins/Cloudflare/v1/defaultContent/{ => Zero Trust}/accessApplication.dash.json (100%) create mode 100644 plugins/Cloudflare/v1/defaultContent/Zero Trust/manifest.json rename plugins/Cloudflare/v1/defaultContent/{ => Zero Trust}/tunnel.dash.json (100%) create mode 100644 plugins/Cloudflare/v1/defaultContent/Zero Trust/turnstileWidget.dash.json delete mode 100644 plugins/Cloudflare/v1/defaultContent/workerBinding.dash.json delete mode 100644 plugins/Cloudflare/v1/defaultContent/workerRoute.dash.json diff --git a/plugins/Cloudflare/v1/correlationRules/relate-resources-to-account.json b/plugins/Cloudflare/v1/correlationRules/relate-resources-to-account.json index b54d9878..ac9ee9c6 100644 --- a/plugins/Cloudflare/v1/correlationRules/relate-resources-to-account.json +++ b/plugins/Cloudflare/v1/correlationRules/relate-resources-to-account.json @@ -14,7 +14,14 @@ "Cloudflare Access Application", "Cloudflare Durable Object Namespace", "Cloudflare Vectorize Index", - "Cloudflare Hyperdrive Config" + "Cloudflare Hyperdrive Config", + "Cloudflare Stream Video", + "Cloudflare Turnstile Widget", + "Cloudflare AI Gateway", + "Cloudflare AutoRAG", + "Cloudflare Container Application", + "Cloudflare Pipeline", + "Cloudflare Realtime App" ] }, "target": { diff --git a/plugins/Cloudflare/v1/custom_types.json b/plugins/Cloudflare/v1/custom_types.json index 862ca596..d6411e94 100644 --- a/plugins/Cloudflare/v1/custom_types.json +++ b/plugins/Cloudflare/v1/custom_types.json @@ -110,5 +110,54 @@ "icon": "plug", "singular": "Worker Binding", "plural": "Worker Bindings" + }, + { + "name": "Cloudflare Stream Video", + "sourceType": "Cloudflare Stream Video", + "icon": "video", + "singular": "Stream Video", + "plural": "Stream Videos" + }, + { + "name": "Cloudflare Turnstile Widget", + "sourceType": "Cloudflare Turnstile Widget", + "icon": "shield-check", + "singular": "Turnstile Widget", + "plural": "Turnstile Widgets" + }, + { + "name": "Cloudflare AI Gateway", + "sourceType": "Cloudflare AI Gateway", + "icon": "brain", + "singular": "AI Gateway", + "plural": "AI Gateways" + }, + { + "name": "Cloudflare AutoRAG", + "sourceType": "Cloudflare AutoRAG", + "icon": "magnifying-glass", + "singular": "AutoRAG", + "plural": "AutoRAGs" + }, + { + "name": "Cloudflare Container Application", + "sourceType": "Cloudflare Container Application", + "icon": "box", + "singular": "Container Application", + "plural": "Container Applications" + }, + { + "name": "Cloudflare Pipeline", + "sourceType": "Cloudflare Pipeline", + "icon": "diagram-project", + "singular": "Pipeline", + "plural": "Pipelines" + }, + { + "name": "Cloudflare Realtime App", + "sourceType": "Cloudflare Realtime App", + "icon": "phone", + "singular": "Realtime App", + "plural": "Realtime Apps" } ] diff --git a/plugins/Cloudflare/v1/dataStreams/aiGatewayCache.json b/plugins/Cloudflare/v1/dataStreams/aiGatewayCache.json new file mode 100644 index 00000000..75f5d853 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/aiGatewayCache.json @@ -0,0 +1,57 @@ +{ + "name": "aiGatewayCache", + "displayName": "AI Gateway Cache", + "description": "Cache hit and miss counts for an AI Gateway", + "tags": ["AI", "Cache"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$gateway:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){aiGatewayCacheAdaptiveGroups(limit:10000,filter:{gateway:$gateway,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){count dimensions{date cacheOp}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "gateway": "{{object.name}}", + "start": "{{timeframe.start.split('T')[0]}}", + "end": "{{timeframe.end.split('T')[0]}}" + } + }, + "pathToData": "data.viewer.accounts.0.aiGatewayCacheAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare AI Gateway"] + } + }, + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { "name": "dimensions.cacheOp", "visible": false }, + { + "name": "cacheStatus", + "displayName": "Cache Status", + "computed": true, + "valueExpression": "{{ $['dimensions.cacheOp'] == 1 ? 'Hit' : 'Miss' }}", + "shape": "string" + }, + { + "name": "count", + "displayName": "Requests", + "shape": "number", + "role": "value" + } + ], + "timeframes": ["last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/aiGatewayErrors.json b/plugins/Cloudflare/v1/dataStreams/aiGatewayErrors.json new file mode 100644 index 00000000..4934fa39 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/aiGatewayErrors.json @@ -0,0 +1,71 @@ +{ + "name": "aiGatewayErrors", + "displayName": "AI Gateway Errors", + "description": "Error counts for an AI Gateway broken down by model or provider", + "tags": ["AI"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$gateway:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){aiGatewayErrorsAdaptiveGroups(limit:10000,filter:{gateway:$gateway,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){count dimensions{date {{breakdown}}}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "gateway": "{{object.name}}", + "start": "{{timeframe.start.split('T')[0]}}", + "end": "{{timeframe.end.split('T')[0]}}" + } + }, + "pathToData": "data.viewer.accounts.0.aiGatewayErrorsAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare AI Gateway"] + } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "model", + "options": [ + { "value": "model", "label": "Model" }, + { "value": "provider", "label": "Provider" } + ] + } + ], + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { "name": "dimensions.model", "visible": false }, + { "name": "dimensions.provider", "visible": false }, + { + "name": "breakdown", + "displayName": "Breakdown", + "computed": true, + "valueExpression": "{{ $['dimensions.model'] || $['dimensions.provider'] || 'Unknown' }}", + "shape": "string" + }, + { + "name": "count", + "displayName": "Errors", + "shape": "number", + "role": "value" + } + ], + "timeframes": ["last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/aiGatewayRequests.json b/plugins/Cloudflare/v1/dataStreams/aiGatewayRequests.json new file mode 100644 index 00000000..4f03cc84 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/aiGatewayRequests.json @@ -0,0 +1,146 @@ +{ + "name": "aiGatewayRequests", + "displayName": "AI Gateway Requests", + "description": "Request volume, token usage, cost and latency for an AI Gateway", + "tags": [ + "AI", + "Analytics" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$gateway:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){aiGatewayRequestsAdaptiveGroups(limit:10000,filter:{gateway:$gateway,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){count dimensions{date {{breakdown}}} sum{cost tokensIn tokensOut totalTokens cachedRequests erroredRequests} quantiles{durationMsP50 durationMsP95}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "gateway": "{{object.name}}", + "start": "{{timeframe.start.split('T')[0]}}", + "end": "{{timeframe.end.split('T')[0]}}" + } + }, + "pathToData": "data.viewer.accounts.0.aiGatewayRequestsAdaptiveGroups", + "expandInnerObjects": true, + "paging": { + "mode": "none" + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare AI Gateway" + ] + } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "model", + "options": [ + { + "value": "model", + "label": "Model" + }, + { + "value": "provider", + "label": "Provider" + }, + { + "value": "statusCode", + "label": "Status Code" + } + ] + } + ], + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "dimensions.model", + "visible": false + }, + { + "name": "dimensions.provider", + "visible": false + }, + { + "name": "dimensions.statusCode", + "visible": false + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "computed": true, + "valueExpression": "{{ $['dimensions.model'] || $['dimensions.provider'] || $['dimensions.statusCode'] || 'Unknown' }}", + "shape": "string" + }, + { + "name": "count", + "displayName": "Requests", + "shape": "number", + "role": "value" + }, + { + "name": "sum.cost", + "displayName": "Cost", + "shape": [ + "number", + { + "decimalPlaces": 2 + } + ] + }, + { + "name": "sum.tokensIn", + "displayName": "Tokens In", + "shape": "number" + }, + { + "name": "sum.tokensOut", + "displayName": "Tokens Out", + "shape": "number" + }, + { + "name": "sum.totalTokens", + "displayName": "Total Tokens", + "shape": "number" + }, + { + "name": "sum.cachedRequests", + "displayName": "Cached Requests", + "shape": "number" + }, + { + "name": "sum.erroredRequests", + "displayName": "Errored Requests", + "shape": "number" + }, + { + "name": "quantiles.durationMsP50", + "displayName": "Median Duration (P50)", + "shape": "milliseconds" + }, + { + "name": "quantiles.durationMsP95", + "displayName": "P95 Duration", + "shape": "milliseconds" + } + ], + "timeframes": [ + "last7days", + "last30days" + ] +} diff --git a/plugins/Cloudflare/v1/dataStreams/aiGateways.json b/plugins/Cloudflare/v1/dataStreams/aiGateways.json new file mode 100644 index 00000000..d95751d2 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/aiGateways.json @@ -0,0 +1,75 @@ +{ + "name": "aiGateways", + "displayName": "AI Gateways", + "description": "AI Gateway instances in an account", + "tags": [ + "AI" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/ai-gateway/gateways", + "postRequestScript": "aiGateways.js", + "paging": { + "mode": "none" + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "gatewayName", + "displayName": "Gateway", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare AI Gateway" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "cacheTtl", + "displayName": "Cache TTL", + "shape": "seconds" + }, + { + "name": "rateLimitingLimit", + "displayName": "Rate Limit", + "shape": "number" + }, + { + "name": "collectLogs", + "displayName": "Collect Logs", + "shape": "boolean" + }, + { + "name": "createdOn", + "displayName": "Created", + "shape": "date" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/auditLogs.json b/plugins/Cloudflare/v1/dataStreams/auditLogs.json new file mode 100644 index 00000000..ca10571e --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/auditLogs.json @@ -0,0 +1,77 @@ +{ + "name": "auditLogs", + "displayName": "Audit Logs", + "description": "Audit log action counts for an account grouped by a selectable dimension", + "tags": [ + "Account", + "Security" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){auditLogsGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count dimensions{date {{breakdown}}}}}}}", + "variables": { + "accountTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "auditLogs.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "actionType", + "options": [ + { "value": "actionType", "label": "Action" }, + { "value": "actorEmail", "label": "Actor" }, + { "value": "resourceType", "label": "Resource Type" } + ] + } + ], + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "actionCount", + "displayName": "Action Count", + "shape": "number", + "role": "value" + } + ], + "timeframes": [ + "last24hours", + "last7days", + "last30days", + "thisMonth", + "lastMonth" + ] +} diff --git a/plugins/Cloudflare/v1/dataStreams/autoragInstances.json b/plugins/Cloudflare/v1/dataStreams/autoragInstances.json new file mode 100644 index 00000000..7d1ce134 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/autoragInstances.json @@ -0,0 +1,70 @@ +{ + "name": "autoragInstances", + "displayName": "AutoRAG Instances", + "description": "AutoRAG retrieval-augmented generation instances in an account", + "tags": [ + "AI" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/autorag/rags", + "postRequestScript": "autoragInstances.js", + "paging": { + "mode": "none" + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "ragName", + "displayName": "AutoRAG", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare AutoRAG" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "status", + "displayName": "Status", + "shape": "string" + }, + { + "name": "source", + "displayName": "Source", + "shape": "string" + }, + { + "name": "createdOn", + "displayName": "Created", + "shape": "date" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/autoragQueries.json b/plugins/Cloudflare/v1/dataStreams/autoragQueries.json new file mode 100644 index 00000000..64c48693 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/autoragQueries.json @@ -0,0 +1,83 @@ +{ + "name": "autoragQueries", + "displayName": "AutoRAG Queries", + "description": "Search and AI Search query volume for an AutoRAG instance", + "tags": ["AI"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$instanceId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){aiSearchAPIAdaptiveGroups(limit:10000,filter:{instanceId:$instanceId,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){count sum{aiSearchCount searchCount} dimensions{date {{breakdown}}}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "instanceId": "{{object.rawId}}", + "start": "{{timeframe.start.split('T')[0]}}", + "end": "{{timeframe.end.split('T')[0]}}" + } + }, + "pathToData": "data.viewer.accounts.0.aiSearchAPIAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare AutoRAG"] + } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "searchType", + "options": [ + { "value": "searchType", "label": "Search Type" }, + { "value": "embeddingModel", "label": "Embedding Model" }, + { "value": "isStream", "label": "Streamed" } + ] + } + ], + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { "name": "dimensions.searchType", "visible": false }, + { "name": "dimensions.embeddingModel", "visible": false }, + { "name": "dimensions.isStream", "visible": false }, + { + "name": "breakdown", + "displayName": "Breakdown", + "computed": true, + "valueExpression": "{{ $['dimensions.searchType'] || $['dimensions.embeddingModel'] || $['dimensions.isStream'] || 'Unknown' }}", + "shape": "string" + }, + { + "name": "count", + "displayName": "Search Events", + "shape": "number", + "role": "value" + }, + { + "name": "sum.aiSearchCount", + "displayName": "AI Searches", + "shape": "number" + }, + { + "name": "sum.searchCount", + "displayName": "Searches", + "shape": "number" + } + ], + "timeframes": ["last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/browserRendering.json b/plugins/Cloudflare/v1/dataStreams/browserRendering.json new file mode 100644 index 00000000..621faf98 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/browserRendering.json @@ -0,0 +1,93 @@ +{ + "name": "browserRendering", + "displayName": "Browser Rendering", + "description": "Browser Rendering session count and duration for an account", + "tags": ["Compute", "AI"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){browserRenderingEventsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count avg{avgConcurrentSessions} min{earliestBrowserStartTime} max{latestBrowserEndTime} dimensions{date sessionId {{breakdown}}}}}}}", + "variables": { + "accountTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "browserRendering.js", + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare Account"] + } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "clientLibrary", + "options": [ + { "value": "clientLibrary", "label": "Client Library" }, + { "value": "recordingMode", "label": "Recording Mode" } + ] + } + ], + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "sessionId", + "displayName": "Session ID", + "shape": "string" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "count", + "displayName": "Events", + "shape": "number" + }, + { + "name": "durationMs", + "displayName": "Session Duration", + "shape": "milliseconds", + "role": "value" + }, + { + "name": "avgConcurrentSessions", + "displayName": "Avg Concurrent Sessions", + "shape": "number" + }, + { + "name": "startTime", + "displayName": "Session Start", + "shape": "date", + "visible": false + }, + { + "name": "endTime", + "displayName": "Session End", + "shape": "date", + "visible": false + } + ], + "timeframes": ["last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/cacheReserveOperations.json b/plugins/Cloudflare/v1/dataStreams/cacheReserveOperations.json new file mode 100644 index 00000000..0be8f98e --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/cacheReserveOperations.json @@ -0,0 +1,62 @@ +{ + "name": "cacheReserveOperations", + "displayName": "Cache Reserve Operations", + "description": "Cache Reserve read, write and delete operation counts for a zone grouped by a selectable dimension", + "tags": ["Zone", "Cache"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){cacheReserveOperationsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){sum{requests}dimensions{datetime {{breakdown}}}}}}}", + "variables": { + "zoneTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "cacheReserveOperations.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "operationClass", + "options": [ + { "value": "operationClass", "label": "Operation Type" }, + { "value": "actionStatus", "label": "Outcome" } + ] + } + ], + "metadata": [ + { + "name": "datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "operationCount", + "displayName": "Operation Count", + "shape": "number", + "role": "value" + } + ], + "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/cacheReserveStorage.json b/plugins/Cloudflare/v1/dataStreams/cacheReserveStorage.json new file mode 100644 index 00000000..ede3d9d3 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/cacheReserveStorage.json @@ -0,0 +1,50 @@ +{ + "name": "cacheReserveStorage", + "displayName": "Cache Reserve Storage", + "description": "Stored object count and payload size held in Cache Reserve for a zone over time", + "tags": ["Zone", "Cache", "Storage"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){cacheReserveStorageAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){max{objectCount storedBytes}dimensions{datetime}}}}}", + "variables": { + "zoneTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "pathToData": "data.viewer.zones.0.cacheReserveStorageAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "max.storedBytes", + "displayName": "Stored Size", + "shape": "bytes", + "role": "value" + }, + { + "name": "max.objectCount", + "displayName": "Objects", + "shape": "number" + } + ], + "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/containerApps.json b/plugins/Cloudflare/v1/dataStreams/containerApps.json new file mode 100644 index 00000000..74f4af0b --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/containerApps.json @@ -0,0 +1,75 @@ +{ + "name": "containerApps", + "displayName": "Container Applications", + "description": "Container applications deployed in an account", + "tags": [ + "Compute" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/containers/applications", + "postRequestScript": "containerApps.js", + "paging": { + "mode": "none" + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "appName", + "displayName": "Application", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare Container Application" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "instances", + "displayName": "Instances", + "shape": "number" + }, + { + "name": "imageName", + "displayName": "Image", + "shape": "string" + }, + { + "name": "schedulingPolicy", + "displayName": "Scheduling Policy", + "shape": "string" + }, + { + "name": "createdOn", + "displayName": "Created", + "shape": "date" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/containerMetrics.json b/plugins/Cloudflare/v1/dataStreams/containerMetrics.json new file mode 100644 index 00000000..1b3e715d --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/containerMetrics.json @@ -0,0 +1,93 @@ +{ + "name": "containerMetrics", + "displayName": "Container Metrics", + "description": "CPU, memory, network and uptime metrics for a Cloudflare Container Application", + "tags": ["Compute"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$applicationId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){containersMetricsAdaptiveGroups(limit:10000,filter:{applicationId:$applicationId,datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count avg{cpuUtilization memory containerUptime} sum{rxBytes txBytes} dimensions{date {{breakdown}}}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "applicationId": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "containerMetrics.js", + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare Container Application"] + } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "region", + "options": [ + { "value": "region", "label": "Region" }, + { "value": "location", "label": "Location" }, + { "value": "procType", "label": "Process Type" } + ] + } + ], + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "count", + "displayName": "Samples", + "shape": "number", + "role": "value" + }, + { + "name": "avgCpuUtilization", + "displayName": "Avg CPU Utilization", + "shape": "number" + }, + { + "name": "avgMemory", + "displayName": "Avg Memory Usage", + "shape": "number" + }, + { + "name": "avgContainerUptimeMs", + "displayName": "Avg Container Uptime", + "shape": "milliseconds" + }, + { + "name": "sumRxBytes", + "displayName": "Bytes Received", + "shape": "bytes" + }, + { + "name": "sumTxBytes", + "displayName": "Bytes Transmitted", + "shape": "bytes" + } + ], + "timeframes": ["last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/d1Queries.json b/plugins/Cloudflare/v1/dataStreams/d1Queries.json new file mode 100644 index 00000000..b15d5dd8 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/d1Queries.json @@ -0,0 +1,94 @@ +{ + "name": "d1Queries", + "displayName": "D1 Query Insights", + "description": "Query counts, rows touched and duration for queries against a D1 database", + "tags": [ + "Database", + "Analytics" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$databaseId:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){d1QueriesAdaptiveGroups(limit:10000,filter:{databaseId:$databaseId,datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){count sum{rowsRead rowsWritten rowsReturned}quantiles{queryDurationMsP50 queryDurationMsP95 queryDurationMsP99}dimensions{datetime databaseRole}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "databaseId": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "pathToData": "data.viewer.accounts.0.d1QueriesAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare D1 Database" + ] + } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "count", + "displayName": "Query Count", + "shape": "number", + "role": "value" + }, + { + "name": "sum.rowsRead", + "displayName": "Rows Read", + "shape": "number" + }, + { + "name": "sum.rowsWritten", + "displayName": "Rows Written", + "shape": "number" + }, + { + "name": "sum.rowsReturned", + "displayName": "Rows Returned", + "shape": "number" + }, + { + "name": "quantiles.queryDurationMsP50", + "displayName": "Query Duration P50", + "shape": ["milliseconds", { "decimalPlaces": 2 }] + }, + { + "name": "quantiles.queryDurationMsP95", + "displayName": "Query Duration P95", + "shape": ["milliseconds", { "decimalPlaces": 2 }] + }, + { + "name": "quantiles.queryDurationMsP99", + "displayName": "Query Duration P99", + "shape": ["milliseconds", { "decimalPlaces": 2 }] + }, + { + "name": "dimensions.databaseRole", + "displayName": "Database Role", + "shape": "string" + } + ], + "timeframes": [ + "last12hours", + "last24hours", + "last7days", + "last30days" + ] +} diff --git a/plugins/Cloudflare/v1/dataStreams/dmarcReports.json b/plugins/Cloudflare/v1/dataStreams/dmarcReports.json new file mode 100644 index 00000000..264e83e1 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/dmarcReports.json @@ -0,0 +1,69 @@ +{ + "name": "dmarcReports", + "displayName": "DMARC Reports", + "description": "DMARC aggregate report message counts and pass rates for a zone grouped by a selectable dimension", + "tags": ["Zone", "Email", "Security"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){dmarcReportsSourcesAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){sum{totalMatchingMessages dmarc} avg{dmarc} dimensions{date {{breakdown}}}}}}}", + "variables": { + "zoneTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "dmarcReports.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "disposition", + "options": [ + { "value": "disposition", "label": "Disposition" }, + { "value": "domain", "label": "Domain" }, + { "value": "sourceOrgName", "label": "Sending Org" }, + { "value": "headerFrom", "label": "Header From" } + ] + } + ], + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "messageCount", + "displayName": "Message Count", + "shape": "number", + "role": "value" + }, + { + "name": "dmarcPassRate", + "displayName": "DMARC Pass Rate", + "shape": ["percent", { "asZeroToOne": true }] + } + ], + "timeframes": ["last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/dnsFirewallAnalytics.json b/plugins/Cloudflare/v1/dataStreams/dnsFirewallAnalytics.json new file mode 100644 index 00000000..d7354406 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/dnsFirewallAnalytics.json @@ -0,0 +1,69 @@ +{ + "name": "dnsFirewallAnalytics", + "displayName": "DNS Firewall Analytics", + "description": "DNS Firewall cluster query counts and median processing time for an account grouped by a selectable dimension", + "tags": ["Security", "DNS"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){dnsFirewallAnalyticsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count quantiles{processingTimeUsP50} dimensions{date {{breakdown}}}}}}}", + "variables": { + "accountTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "dnsFirewallAnalytics.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Account"] } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "responseCode", + "options": [ + { "value": "responseCode", "label": "Response Code" }, + { "value": "queryType", "label": "Query Type" }, + { "value": "responseReason", "label": "Response Reason" }, + { "value": "clusterName", "label": "Cluster" } + ] + } + ], + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "queries", + "displayName": "Queries", + "shape": "number", + "role": "value" + }, + { + "name": "medianProcessingTimeMs", + "displayName": "Median Processing Time", + "shape": "milliseconds" + } + ], + "timeframes": ["last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/durableObjectSubrequests.json b/plugins/Cloudflare/v1/dataStreams/durableObjectSubrequests.json new file mode 100644 index 00000000..5449a3e0 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/durableObjectSubrequests.json @@ -0,0 +1,59 @@ +{ + "name": "durableObjectSubrequests", + "displayName": "Durable Object Subrequests", + "description": "Outbound uncached fetch subrequest body size for a Durable Object namespace", + "tags": [ + "Workers", + "Analytics" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$namespaceId:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){durableObjectsSubrequestsAdaptiveGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){sum{requestBodySizeUncached}dimensions{datetime}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "namespaceId": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "pathToData": "data.viewer.accounts.0.durableObjectsSubrequestsAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Durable Object Namespace" + ] + } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "sum.requestBodySizeUncached", + "displayName": "Uncached Subrequest Body Size", + "shape": "bytes", + "role": "value" + } + ], + "timeframes": [ + "last12hours", + "last24hours", + "last7days", + "last30days" + ] +} diff --git a/plugins/Cloudflare/v1/dataStreams/emailRouting.json b/plugins/Cloudflare/v1/dataStreams/emailRouting.json new file mode 100644 index 00000000..f3a0acf2 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/emailRouting.json @@ -0,0 +1,64 @@ +{ + "name": "emailRouting", + "displayName": "Email Routing", + "description": "Email Routing message counts for a zone grouped by a selectable dimension", + "tags": ["Zone", "Email"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){emailRoutingAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count dimensions{date {{breakdown}}}}}}}", + "variables": { + "zoneTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "emailRouting.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "action", + "options": [ + { "value": "action", "label": "Action" }, + { "value": "status", "label": "Status" }, + { "value": "spf", "label": "SPF Result" }, + { "value": "dmarc", "label": "DMARC Result" } + ] + } + ], + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "messageCount", + "displayName": "Message Count", + "shape": "number", + "role": "value" + } + ], + "timeframes": ["last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/gatewayNetworkSessions.json b/plugins/Cloudflare/v1/dataStreams/gatewayNetworkSessions.json new file mode 100644 index 00000000..557ef356 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/gatewayNetworkSessions.json @@ -0,0 +1,66 @@ +{ + "name": "gatewayNetworkSessions", + "displayName": "Gateway Network Sessions", + "description": "Zero Trust Gateway network (L4) session counts for an account grouped by a selectable dimension", + "tags": ["Security", "Network"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayL4SessionsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date {{breakdown}} }}}}}", + "variables": { + "accountTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "gatewayNetworkSessions.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Account"] } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "action", + "options": [ + { "value": "action", "label": "Action" }, + { "value": "destinationIp", "label": "Destination IP" }, + { "value": "destinationPort", "label": "Destination Port" }, + { "value": "transportProtocol", "label": "Protocol" }, + { "value": "deviceId", "label": "Device" }, + { "value": "ruleId", "label": "Policy" } + ] + } + ], + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "sessionCount", + "displayName": "Session Count", + "shape": "number", + "role": "value" + } + ], + "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/imagesRequests.json b/plugins/Cloudflare/v1/dataStreams/imagesRequests.json new file mode 100644 index 00000000..347c791b --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/imagesRequests.json @@ -0,0 +1,44 @@ +{ + "name": "imagesRequests", + "displayName": "Images Requests", + "description": "Daily Cloudflare Images request counts for an account", + "tags": ["Media"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){imagesRequestsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){sum{requests}dimensions{date}}}}}", + "variables": { + "accountTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "imagesRequests.js", + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Account"] } + }, + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "requests", + "displayName": "Requests", + "shape": "number", + "role": "value" + } + ], + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/imagesTransformations.json b/plugins/Cloudflare/v1/dataStreams/imagesTransformations.json new file mode 100644 index 00000000..dec2be8f --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/imagesTransformations.json @@ -0,0 +1,44 @@ +{ + "name": "imagesTransformations", + "displayName": "Images Unique Transformations", + "description": "Daily count of unique image transformations served for an account", + "tags": ["Media"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){imagesUniqueTransformations(limit:10000,filter:{date_geq:$start,date_leq:$end},orderBy:[date_ASC]){date transformations}}}}", + "variables": { + "accountTag": "{{object.rawId}}", + "start": "{{timeframe.start.split('T')[0]}}", + "end": "{{timeframe.end.split('T')[0]}}" + } + }, + "postRequestScript": "imagesTransformations.js", + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Account"] } + }, + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "transformations", + "displayName": "Unique Transformations", + "shape": "number", + "role": "value" + } + ], + "timeframes": ["last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/pagesFunctionsInvocations.json b/plugins/Cloudflare/v1/dataStreams/pagesFunctionsInvocations.json new file mode 100644 index 00000000..d8518fc4 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/pagesFunctionsInvocations.json @@ -0,0 +1,78 @@ +{ + "name": "pagesFunctionsInvocations", + "displayName": "Pages Functions Invocations", + "description": "Requests, errors and CPU time for the Pages Functions running in an account, by function", + "tags": ["Pages", "Analytics"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){pagesFunctionsInvocationsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){sum{requests errors subrequests}quantiles{cpuTimeP50 cpuTimeP99}dimensions{datetime scriptName status}}}}}", + "variables": { + "accountTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "pathToData": "data.viewer.accounts.0.pagesFunctionsInvocationsAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Account"] } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "dimensions.scriptName", + "displayName": "Function", + "shape": "string", + "role": "label" + }, + { + "name": "dimensions.status", + "displayName": "Status", + "shape": "string" + }, + { + "name": "sum.requests", + "displayName": "Requests", + "shape": "number", + "role": "value" + }, + { "name": "sum.errors", "displayName": "Errors", "shape": "number" }, + { + "name": "sum.subrequests", + "displayName": "Subrequests", + "shape": "number" + }, + { "name": "quantiles.cpuTimeP50", "visible": false }, + { "name": "quantiles.cpuTimeP99", "visible": false }, + { + "name": "cpuTimeP50Ms", + "displayName": "CPU Time P50", + "computed": true, + "valueExpression": "{{ Number($['quantiles.cpuTimeP50']) / 1000 }}", + "shape": ["milliseconds", { "decimalPlaces": 2 }] + }, + { + "name": "cpuTimeP99Ms", + "displayName": "CPU Time P99", + "computed": true, + "valueExpression": "{{ Number($['quantiles.cpuTimeP99']) / 1000 }}", + "shape": ["milliseconds", { "decimalPlaces": 2 }] + } + ], + "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/pipelineIngestion.json b/plugins/Cloudflare/v1/dataStreams/pipelineIngestion.json new file mode 100644 index 00000000..ffd25320 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/pipelineIngestion.json @@ -0,0 +1,59 @@ +{ + "name": "pipelineIngestion", + "displayName": "Pipeline Ingestion", + "description": "Records and bytes ingested by a Cloudflare Pipeline", + "tags": ["Compute"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$pipelineId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){pipelinesIngestionAdaptiveGroups(limit:10000,filter:{pipelineId:$pipelineId,datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count sum{ingestedBytes ingestedRecords} dimensions{date}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "pipelineId": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "pathToData": "data.viewer.accounts.0.pipelinesIngestionAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare Pipeline"] + } + }, + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "sum.ingestedRecords", + "displayName": "Records Ingested", + "shape": "number", + "role": "value" + }, + { + "name": "sum.ingestedBytes", + "displayName": "Bytes Ingested", + "shape": "bytes" + }, + { + "name": "count", + "displayName": "Ingestion Operations", + "shape": "number" + } + ], + "timeframes": ["last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/pipelines.json b/plugins/Cloudflare/v1/dataStreams/pipelines.json new file mode 100644 index 00000000..ac612c62 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/pipelines.json @@ -0,0 +1,65 @@ +{ + "name": "pipelines", + "displayName": "Pipelines", + "description": "Cloudflare Pipelines defined in an account", + "tags": [ + "Compute" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/pipelines", + "postRequestScript": "pipelines.js", + "paging": { + "mode": "none" + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "pipelineName", + "displayName": "Pipeline", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare Pipeline" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "endpoint", + "displayName": "Endpoint", + "shape": "string" + }, + { + "name": "createdOn", + "displayName": "Created", + "shape": "date" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/queueConsumerMetrics.json b/plugins/Cloudflare/v1/dataStreams/queueConsumerMetrics.json new file mode 100644 index 00000000..806a8974 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/queueConsumerMetrics.json @@ -0,0 +1,59 @@ +{ + "name": "queueConsumerMetrics", + "displayName": "Queue Consumer Metrics", + "description": "Average consumer concurrency for a Queue", + "tags": [ + "Queues", + "Analytics" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$queueId:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){queueConsumerMetricsAdaptiveGroups(limit:10000,filter:{queueId:$queueId,datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){avg{concurrency}dimensions{datetime}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "queueId": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "pathToData": "data.viewer.accounts.0.queueConsumerMetricsAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Queue" + ] + } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "avg.concurrency", + "displayName": "Avg Consumer Concurrency", + "shape": ["number", { "decimalPlaces": 2 }], + "role": "value" + } + ], + "timeframes": [ + "last12hours", + "last24hours", + "last7days", + "last30days" + ] +} diff --git a/plugins/Cloudflare/v1/dataStreams/realtimeApps.json b/plugins/Cloudflare/v1/dataStreams/realtimeApps.json new file mode 100644 index 00000000..a3d858aa --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/realtimeApps.json @@ -0,0 +1,65 @@ +{ + "name": "realtimeApps", + "displayName": "Realtime Apps", + "description": "Cloudflare Realtime (Calls) applications in an account", + "tags": [ + "Media" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/calls/apps", + "postRequestScript": "realtimeApps.js", + "paging": { + "mode": "none" + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "appName", + "displayName": "Application", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare Realtime App" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "createdOn", + "displayName": "Created", + "shape": "date" + }, + { + "name": "modifiedOn", + "displayName": "Modified", + "shape": "date" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/realtimeUsage.json b/plugins/Cloudflare/v1/dataStreams/realtimeUsage.json new file mode 100644 index 00000000..1c931ffa --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/realtimeUsage.json @@ -0,0 +1,60 @@ +{ + "name": "realtimeUsage", + "displayName": "Realtime Usage", + "description": "Bandwidth sent and received by a Cloudflare Realtime App, broken down by track type", + "tags": ["Media"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$appId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){callsUsageAdaptiveGroups(limit:10000,filter:{appId:$appId,datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){sum{egressBytes ingressBytes} dimensions{date trackType}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "appId": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "pathToData": "data.viewer.accounts.0.callsUsageAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare Realtime App"] + } + }, + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "dimensions.trackType", + "displayName": "Track Type", + "shape": "string", + "role": "label" + }, + { + "name": "sum.egressBytes", + "displayName": "Bytes Sent", + "shape": "bytes", + "role": "value" + }, + { + "name": "sum.ingressBytes", + "displayName": "Bytes Received", + "shape": "bytes" + } + ], + "timeframes": ["last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/aiGateways.js b/plugins/Cloudflare/v1/dataStreams/scripts/aiGateways.js new file mode 100644 index 00000000..d3d40d8c --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/aiGateways.js @@ -0,0 +1,17 @@ +// Gateway ids are only unique within an account, so the account id is prefixed +// onto the id to form a globally-unique sourceId. Field names are written +// defensively: no AI Gateway exists in the test account, so the response shape +// is taken from Cloudflare's docs rather than observed. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((g) => ({ + sourceId: `${accountId}:${g.id || g.name}`, + gatewayName: g.id || g.name || "", + accountId: accountId, + cacheTtl: typeof g.cache_ttl === "number" ? g.cache_ttl : null, + rateLimitingLimit: + typeof g.rate_limiting_limit === "number" ? g.rate_limiting_limit : null, + collectLogs: Boolean(g.collect_logs), + createdOn: g.created_at || g.created_on, +})); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/auditLogs.js b/plugins/Cloudflare/v1/dataStreams/scripts/auditLogs.js new file mode 100644 index 00000000..641f2945 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/auditLogs.js @@ -0,0 +1,34 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + +// dataStreams/scripts/auditLogs.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the breakdown value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.actionType vs dimensions.actorEmail vs dimensions.resourceType). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.accounts && + data.data.viewer.accounts[0] && + data.data.viewer.accounts[0].auditLogsGroups) || + []; + +result = groups.map((row) => { + const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; + const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); + + return { + date: row.dimensions && row.dimensions.date, + breakdown: label, + actionCount: Number((row.count !== undefined && row.count !== null ? row.count : 0)) || 0 + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/autoragInstances.js b/plugins/Cloudflare/v1/dataStreams/scripts/autoragInstances.js new file mode 100644 index 00000000..61a8795f --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/autoragInstances.js @@ -0,0 +1,13 @@ +// Written defensively: no AutoRAG instance exists in the test account, so the +// response shape follows Cloudflare's docs and falls back across likely keys. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((r) => ({ + sourceId: r.id || `${accountId}:${r.name}`, + ragName: r.name || r.id || "", + accountId: accountId, + status: r.status || "", + source: r.source || (r.data_source && r.data_source.type) || "", + createdOn: r.created_at || r.created_on, +})); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/browserRendering.js b/plugins/Cloudflare/v1/dataStreams/scripts/browserRendering.js new file mode 100644 index 00000000..8ac020bb --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/browserRendering.js @@ -0,0 +1,49 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + +// dataStreams/scripts/browserRendering.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the dimension value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.clientLibrary vs dimensions.recordingMode). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. +// +// Rows are grouped by date + sessionId (+ the chosen breakdown dimension), so each row's +// min/max aggregates collapse to that one session's actual start/end time - used to derive +// a genuine per-session duration, which the API has no single field for. + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.accounts && + data.data.viewer.accounts[0] && + data.data.viewer.accounts[0].browserRenderingEventsAdaptiveGroups) || + []; + +result = groups.map((row) => { + const dims = row.dimensions || {}; + const rawValue = dimensionKey ? dims[dimensionKey] : undefined; + const breakdown = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); + + const startTime = row.min && row.min.earliestBrowserStartTime; + const endTime = row.max && row.max.latestBrowserEndTime; + const durationMs = + startTime && endTime ? new Date(endTime).getTime() - new Date(startTime).getTime() : null; + + return { + date: dims.date, + sessionId: dims.sessionId, + breakdown: breakdown, + count: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0, + durationMs: durationMs, + avgConcurrentSessions: Number((row.avg && row.avg.avgConcurrentSessions) || 0) || 0, + startTime: startTime, + endTime: endTime + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/cacheReserveOperations.js b/plugins/Cloudflare/v1/dataStreams/scripts/cacheReserveOperations.js new file mode 100644 index 00000000..9b6b124f --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/cacheReserveOperations.js @@ -0,0 +1,34 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + +// dataStreams/scripts/cacheReserveOperations.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the dimension value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.operationClass vs dimensions.actionStatus). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.zones && + data.data.viewer.zones[0] && + data.data.viewer.zones[0].cacheReserveOperationsAdaptiveGroups) || + []; + +result = groups.map((row) => { + const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; + const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); + + return { + datetime: row.dimensions && row.dimensions.datetime, + breakdown: label, + operationCount: Number((row.sum && row.sum.requests !== undefined ? row.sum.requests : 0)) || 0 + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/containerApps.js b/plugins/Cloudflare/v1/dataStreams/scripts/containerApps.js new file mode 100644 index 00000000..e7e54623 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/containerApps.js @@ -0,0 +1,17 @@ +// Written defensively: no container application exists in the test account, so +// the response shape follows Cloudflare's docs and falls back across likely keys. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((a) => { + const cfg = a.configuration || {}; + return { + sourceId: a.id || `${accountId}:${a.name}`, + appName: a.name || a.id || "", + accountId: accountId, + instances: typeof a.instances === "number" ? a.instances : null, + imageName: cfg.image || a.image || "", + schedulingPolicy: a.scheduling_policy || "", + createdOn: a.created_at || a.created_on, + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/containerMetrics.js b/plugins/Cloudflare/v1/dataStreams/scripts/containerMetrics.js new file mode 100644 index 00000000..7beb34ce --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/containerMetrics.js @@ -0,0 +1,42 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + +// dataStreams/scripts/containerMetrics.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the dimension value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.region vs dimensions.location vs dimensions.procType). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.accounts && + data.data.viewer.accounts[0] && + data.data.viewer.accounts[0].containersMetricsAdaptiveGroups) || + []; + +result = groups.map((row) => { + const dims = row.dimensions || {}; + const rawValue = dimensionKey ? dims[dimensionKey] : undefined; + const breakdown = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); + const avg = row.avg || {}; + const sum = row.sum || {}; + + return { + date: dims.date, + breakdown: breakdown, + count: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0, + avgCpuUtilization: Number(avg.cpuUtilization || 0) || 0, + avgMemory: Number(avg.memory || 0) || 0, + avgContainerUptimeMs: Number(avg.containerUptime || 0) || 0, + sumRxBytes: Number(sum.rxBytes || 0) || 0, + sumTxBytes: Number(sum.txBytes || 0) || 0 + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/dmarcReports.js b/plugins/Cloudflare/v1/dataStreams/scripts/dmarcReports.js new file mode 100644 index 00000000..b397f0b9 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/dmarcReports.js @@ -0,0 +1,35 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + +// dataStreams/scripts/dmarcReports.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the dimension value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.disposition vs dimensions.domain vs ...). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.zones && + data.data.viewer.zones[0] && + data.data.viewer.zones[0].dmarcReportsSourcesAdaptiveGroups) || + []; + +result = groups.map((row) => { + const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; + const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); + + return { + date: row.dimensions && row.dimensions.date, + breakdown: label, + messageCount: Number((row.sum && row.sum.totalMatchingMessages) || 0) || 0, + dmarcPassRate: Number((row.avg && row.avg.dmarc) || 0) || 0 + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/dnsFirewallAnalytics.js b/plugins/Cloudflare/v1/dataStreams/scripts/dnsFirewallAnalytics.js new file mode 100644 index 00000000..c4421ca3 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/dnsFirewallAnalytics.js @@ -0,0 +1,48 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + +// dataStreams/scripts/dnsFirewallAnalytics.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the dimension value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.responseCode vs dimensions.queryType vs ...). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. +// processingTimeUsP50 is reported by Cloudflare in microseconds; convert to milliseconds. +// +// Cloudflare answers a failed GraphQL query with HTTP 200 and a populated top-level +// `errors` array. A postRequestScript bypasses the stream's declarative `errorHandling`, +// so without this check a genuine failure would silently shape to zero rows instead of +// surfacing as an error. +const graphqlErrors = data && Array.isArray(data.errors) ? data.errors : []; +if (graphqlErrors.length) { + throw new Error( + "Cloudflare GraphQL error: " + + graphqlErrors.map((e) => (e && e.message) || JSON.stringify(e)).join(" | ") + ); +} + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.accounts && + data.data.viewer.accounts[0] && + data.data.viewer.accounts[0].dnsFirewallAnalyticsAdaptiveGroups) || + []; + +result = groups.map((row) => { + const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; + const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); + + return { + date: row.dimensions && row.dimensions.date, + breakdown: label, + queries: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0, + medianProcessingTimeMs: Number((row.quantiles && row.quantiles.processingTimeUsP50) || 0) / 1000 + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/emailRouting.js b/plugins/Cloudflare/v1/dataStreams/scripts/emailRouting.js new file mode 100644 index 00000000..837d5ff1 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/emailRouting.js @@ -0,0 +1,34 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + +// dataStreams/scripts/emailRouting.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the dimension value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.action vs dimensions.status vs ...). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.zones && + data.data.viewer.zones[0] && + data.data.viewer.zones[0].emailRoutingAdaptiveGroups) || + []; + +result = groups.map((row) => { + const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; + const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); + + return { + date: row.dimensions && row.dimensions.date, + breakdown: label, + messageCount: Number((row.count !== undefined && row.count !== null ? row.count : 0)) || 0 + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/gatewayDnsQueries.js b/plugins/Cloudflare/v1/dataStreams/scripts/gatewayDnsQueries.js index 93b2155b..8b11f27b 100644 --- a/plugins/Cloudflare/v1/dataStreams/scripts/gatewayDnsQueries.js +++ b/plugins/Cloudflare/v1/dataStreams/scripts/gatewayDnsQueries.js @@ -1,3 +1,10 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + // dataStreams/scripts/gatewayDnsQueries.js // The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the // key holding the dimension value inside each row's `dimensions` object varies with the diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/gatewayHttpRequests.js b/plugins/Cloudflare/v1/dataStreams/scripts/gatewayHttpRequests.js index e27fafda..7cebe51e 100644 --- a/plugins/Cloudflare/v1/dataStreams/scripts/gatewayHttpRequests.js +++ b/plugins/Cloudflare/v1/dataStreams/scripts/gatewayHttpRequests.js @@ -1,3 +1,10 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + // dataStreams/scripts/gatewayHttpRequests.js // The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the // key holding the dimension value inside each row's `dimensions` object varies with the diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/gatewayNetworkSessions.js b/plugins/Cloudflare/v1/dataStreams/scripts/gatewayNetworkSessions.js new file mode 100644 index 00000000..fcd76918 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/gatewayNetworkSessions.js @@ -0,0 +1,39 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + +// dataStreams/scripts/gatewayNetworkSessions.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the dimension value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.action vs dimensions.destinationIp vs ...). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.accounts && + data.data.viewer.accounts[0] && + data.data.viewer.accounts[0].gatewayL4SessionsAdaptiveGroups) || + []; + +result = groups.map((row) => { + const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; + const label = + rawValue === undefined || rawValue === null || rawValue === "" || (Array.isArray(rawValue) && rawValue.length === 0) + ? "Unknown" + : Array.isArray(rawValue) + ? rawValue.join(", ") + : String(rawValue); + + return { + date: row.dimensions && row.dimensions.date, + breakdown: label, + sessionCount: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0 + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/imagesRequests.js b/plugins/Cloudflare/v1/dataStreams/scripts/imagesRequests.js new file mode 100644 index 00000000..f1ff0d1d --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/imagesRequests.js @@ -0,0 +1,27 @@ +// dataStreams/scripts/imagesRequests.js +// Cloudflare answers a failed GraphQL query with HTTP 200 and a populated `errors` array, +// so the request never looks like a failure and the stream's `errorHandling` does not +// reliably fire on it (confirmed against this endpoint's imagesTransformationsAdaptiveGroups +// node, which returns exactly this shape). Check for it explicitly so a broken/over-wide +// query surfaces as a real error instead of silently shaping to a degenerate row. +const graphqlErrors = (data && data.errors) || []; +if (graphqlErrors.length) { + throw new Error( + "Cloudflare GraphQL error: " + + graphqlErrors.map((e) => (e && e.message) || JSON.stringify(e)).join(" | ") + ); +} + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.accounts && + data.data.viewer.accounts[0] && + data.data.viewer.accounts[0].imagesRequestsAdaptiveGroups) || + []; + +result = groups.map((row) => ({ + date: row.dimensions && row.dimensions.date, + requests: Number((row.sum && row.sum.requests) || 0) || 0 +})); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/imagesTransformations.js b/plugins/Cloudflare/v1/dataStreams/scripts/imagesTransformations.js new file mode 100644 index 00000000..19ead6ad --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/imagesTransformations.js @@ -0,0 +1,20 @@ +// Cloudflare's GraphQL API answers HTTP 200 even when the query failed, and the +// stream-level errorHandling does not reliably fire for that case, so the error +// is raised here explicitly rather than shaping to a misleading empty result. +// +// Note this uses imagesUniqueTransformations, not imagesTransformationsAdaptiveGroups: +// the latter returns INTERNAL_SERVER_ERROR from Cloudflare for every query shape +// and timeframe tested, on every account tested. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + +const accounts = + (data && data.data && data.data.viewer && data.data.viewer.accounts) || []; +const rows = (accounts[0] || {}).imagesUniqueTransformations || []; + +result = rows.map((r) => ({ + date: r.date, + transformations: + typeof r.transformations === "number" ? r.transformations : null, +})); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/pipelines.js b/plugins/Cloudflare/v1/dataStreams/scripts/pipelines.js new file mode 100644 index 00000000..55bdb4f1 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/pipelines.js @@ -0,0 +1,12 @@ +// Written defensively: no pipeline exists in the test account, so the response +// shape follows Cloudflare's docs and falls back across likely keys. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((p) => ({ + sourceId: p.id || `${accountId}:${p.name}`, + pipelineName: p.name || p.id || "", + accountId: accountId, + endpoint: p.endpoint || "", + createdOn: p.created_at || p.created_on, +})); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/realtimeApps.js b/plugins/Cloudflare/v1/dataStreams/scripts/realtimeApps.js new file mode 100644 index 00000000..d22393a3 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/realtimeApps.js @@ -0,0 +1,12 @@ +// Written defensively: no Realtime application exists in the test account, so +// the response shape follows Cloudflare's docs and falls back across likely keys. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((a) => ({ + sourceId: a.uid || a.id, + appName: a.name || a.uid || a.id || "", + accountId: accountId, + createdOn: a.created, + modifiedOn: a.modified, +})); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/rumPageLoads.js b/plugins/Cloudflare/v1/dataStreams/scripts/rumPageLoads.js index eda82c73..36a37fbc 100644 --- a/plugins/Cloudflare/v1/dataStreams/scripts/rumPageLoads.js +++ b/plugins/Cloudflare/v1/dataStreams/scripts/rumPageLoads.js @@ -1,3 +1,10 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + // dataStreams/scripts/rumPageLoads.js // The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the // key holding the dimension value inside each row's `dimensions` object varies with the diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/streamCmcd.js b/plugins/Cloudflare/v1/dataStreams/scripts/streamCmcd.js new file mode 100644 index 00000000..2d81407f --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/streamCmcd.js @@ -0,0 +1,38 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + +// dataStreams/scripts/streamCmcd.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the dimension value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.country vs dimensions.resolution vs dimensions.streamType). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.accounts && + data.data.viewer.accounts[0] && + data.data.viewer.accounts[0].streamCMCDAdaptiveGroups) || + []; + +result = groups.map((row) => { + const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; + const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); + const avg = row.avg || {}; + + return { + date: row.dimensions && row.dimensions.date, + breakdown: label, + sampleCount: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0, + avgBufferingDurationMs: Number(avg.bufferStarvationDuration) || 0, + avgStartupBufferingDurationMs: Number(avg.initialBufferStarvationDuration) || 0, + avgEncodedBitrate: Number(avg.encodedBitrate) || 0, + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/streamVideos.js b/plugins/Cloudflare/v1/dataStreams/scripts/streamVideos.js new file mode 100644 index 00000000..8b8b2d49 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/streamVideos.js @@ -0,0 +1,21 @@ +// Stream nests the video name under meta and the processing state under status, +// which expandInnerObjects cannot reach through a script-free config, so both +// are flattened here alongside the account id from the scoped object. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((v) => { + const meta = v.meta || {}; + const status = v.status || {}; + return { + sourceId: v.uid, + videoName: meta.name || v.uid, + accountId: accountId, + statusState: status.state || "", + duration: typeof v.duration === "number" ? v.duration : null, + size: typeof v.size === "number" ? v.size : null, + readyToStream: Boolean(v.readyToStream), + createdOn: v.created, + preview: v.preview || "", + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/turnstileChallenges.js b/plugins/Cloudflare/v1/dataStreams/scripts/turnstileChallenges.js new file mode 100644 index 00000000..b95030d8 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/turnstileChallenges.js @@ -0,0 +1,39 @@ +// dataStreams/scripts/turnstileChallenges.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the breakdown value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.eventType vs dimensions.action). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. +// +// Cloudflare answers a failed GraphQL query with HTTP 200 and a populated `errors` array, +// so the request never looks like a failure and the stream's `errorHandling` does not +// reliably fire on it. Check for it explicitly so a broken/over-wide query surfaces as a +// real error instead of silently shaping to zero rows. +const graphqlErrors = (data && data.errors) || []; +if (graphqlErrors.length) { + throw new Error( + "Cloudflare GraphQL error: " + + graphqlErrors.map((e) => (e && e.message) || JSON.stringify(e)).join(" | ") + ); +} + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.accounts && + data.data.viewer.accounts[0] && + data.data.viewer.accounts[0].turnstileAdaptiveGroups) || + []; + +result = groups.map((row) => { + const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; + const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); + + return { + date: row.dimensions && row.dimensions.date, + breakdown: label, + challenges: Number((row.count !== undefined && row.count !== null ? row.count : 0)) || 0 + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/turnstileWidgets.js b/plugins/Cloudflare/v1/dataStreams/scripts/turnstileWidgets.js new file mode 100644 index 00000000..6efa14dc --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/turnstileWidgets.js @@ -0,0 +1,16 @@ +// The Turnstile sitekey is the widget's stable identifier and is globally +// unique, so it doubles as the sourceId. +const accountId = + (context.objects && context.objects[0] && context.objects[0].rawId) || ""; + +result = ((data && data.result) || []).map((w) => ({ + sourceId: w.sitekey, + widgetName: w.name || w.sitekey, + accountId: accountId, + mode: w.mode || "", + region: w.region || "", + domains: (w.domains || []).join(", "), + botFightMode: Boolean(w.bot_fight_mode), + createdOn: w.created_on, + modifiedOn: w.modified_on, +})); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/workersAiInference.js b/plugins/Cloudflare/v1/dataStreams/scripts/workersAiInference.js index 2a0f213c..5cf1c49a 100644 --- a/plugins/Cloudflare/v1/dataStreams/scripts/workersAiInference.js +++ b/plugins/Cloudflare/v1/dataStreams/scripts/workersAiInference.js @@ -1,3 +1,10 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + // dataStreams/scripts/workersAiInference.js // The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the // key holding the breakdown value inside each row's `dimensions` object varies with the diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/zoneDnsAnalytics.js b/plugins/Cloudflare/v1/dataStreams/scripts/zoneDnsAnalytics.js index 0a08a103..ec34883f 100644 --- a/plugins/Cloudflare/v1/dataStreams/scripts/zoneDnsAnalytics.js +++ b/plugins/Cloudflare/v1/dataStreams/scripts/zoneDnsAnalytics.js @@ -1,3 +1,10 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + // dataStreams/scripts/zoneDnsAnalytics.js // The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the // key holding the dimension value inside each row's `dimensions` object varies with the diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/zoneFirewallEvents.js b/plugins/Cloudflare/v1/dataStreams/scripts/zoneFirewallEvents.js index 94246d9b..bd7759ab 100644 --- a/plugins/Cloudflare/v1/dataStreams/scripts/zoneFirewallEvents.js +++ b/plugins/Cloudflare/v1/dataStreams/scripts/zoneFirewallEvents.js @@ -1,3 +1,10 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + // dataStreams/scripts/zoneFirewallEvents.js // The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the // key holding the selected dimension's value inside each row's `dimensions` object varies diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/zoneNelReports.js b/plugins/Cloudflare/v1/dataStreams/scripts/zoneNelReports.js new file mode 100644 index 00000000..f1a142ac --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/zoneNelReports.js @@ -0,0 +1,46 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + +// dataStreams/scripts/zoneNelReports.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the dimension value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.type vs dimensions.phase vs ...). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. +// +// Cloudflare answers a failed GraphQL query (e.g. NEL not entitled on this zone's plan) +// with HTTP 200 and a populated top-level `errors` array. A postRequestScript bypasses +// the stream's declarative `errorHandling`, so without this check a genuine failure +// would silently shape to zero rows instead of surfacing as an error. +const graphqlErrors = data && Array.isArray(data.errors) ? data.errors : []; +if (graphqlErrors.length) { + throw new Error( + "Cloudflare GraphQL error: " + + graphqlErrors.map((e) => (e && e.message) || JSON.stringify(e)).join(" | ") + ); +} + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.zones && + data.data.viewer.zones[0] && + data.data.viewer.zones[0].nelReportsAdaptiveGroups) || + []; + +result = groups.map((row) => { + const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; + const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); + + return { + date: row.dimensions && row.dimensions.date, + breakdown: label, + events: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0 + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/zonePageShield.js b/plugins/Cloudflare/v1/dataStreams/scripts/zonePageShield.js new file mode 100644 index 00000000..7862babf --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/scripts/zonePageShield.js @@ -0,0 +1,46 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + +// dataStreams/scripts/zonePageShield.js +// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the +// key holding the dimension value inside each row's `dimensions` object varies with the +// user-selected breakdown (dimensions.resourceType vs dimensions.urlHost vs ...). +// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. +// +// Cloudflare answers a failed GraphQL query (e.g. Page Shield not entitled on this +// zone's plan) with HTTP 200 and a populated top-level `errors` array. A postRequestScript +// bypasses the stream's declarative `errorHandling`, so without this check a genuine +// failure would silently shape to zero rows instead of surfacing as an error. +const graphqlErrors = data && Array.isArray(data.errors) ? data.errors : []; +if (graphqlErrors.length) { + throw new Error( + "Cloudflare GraphQL error: " + + graphqlErrors.map((e) => (e && e.message) || JSON.stringify(e)).join(" | ") + ); +} + +const dimensionKey = context.config && context.config.breakdown; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.zones && + data.data.viewer.zones[0] && + data.data.viewer.zones[0].pageShieldReportsAdaptiveGroups) || + []; + +result = groups.map((row) => { + const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; + const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); + + return { + date: row.dimensions && row.dimensions.date, + breakdown: label, + events: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0 + }; +}); diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/zoneTrafficBreakdown.js b/plugins/Cloudflare/v1/dataStreams/scripts/zoneTrafficBreakdown.js index c1868df5..0873816c 100644 --- a/plugins/Cloudflare/v1/dataStreams/scripts/zoneTrafficBreakdown.js +++ b/plugins/Cloudflare/v1/dataStreams/scripts/zoneTrafficBreakdown.js @@ -1,3 +1,10 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + // dataStreams/scripts/zoneTrafficBreakdown.js // The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the // key holding the dimension value inside each row's `dimensions` object varies with the diff --git a/plugins/Cloudflare/v1/dataStreams/streamCmcd.json b/plugins/Cloudflare/v1/dataStreams/streamCmcd.json new file mode 100644 index 00000000..faa8c66d --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/streamCmcd.json @@ -0,0 +1,83 @@ +{ + "name": "streamCmcd", + "displayName": "Stream Playback Quality", + "description": "Daily playback quality metrics for a Cloudflare Stream video, grouped by a selectable dimension", + "tags": ["Media"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$videoId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){streamCMCDAdaptiveGroups(limit:10000,filter:{videoId:$videoId,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){count avg{bufferStarvationDuration initialBufferStarvationDuration encodedBitrate} dimensions{date {{breakdown}}}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "videoId": "{{object.rawId}}", + "start": "{{timeframe.start.split('T')[0]}}", + "end": "{{timeframe.end.split('T')[0]}}" + } + }, + "postRequestScript": "streamCmcd.js", + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare Stream Video"] + } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "country", + "options": [ + { "value": "country", "label": "Country" }, + { "value": "resolution", "label": "Resolution" }, + { "value": "streamType", "label": "Stream Type" } + ] + } + ], + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "sampleCount", + "displayName": "Sample Count", + "shape": "number" + }, + { + "name": "avgBufferingDurationMs", + "displayName": "Avg Buffering Duration", + "shape": "milliseconds", + "role": "value" + }, + { + "name": "avgStartupBufferingDurationMs", + "displayName": "Avg Startup Buffering Duration", + "shape": "milliseconds" + }, + { + "name": "avgEncodedBitrate", + "displayName": "Avg Encoded Bitrate", + "shape": "number" + } + ], + "timeframes": ["last24hours", "last7days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/streamMinutesViewed.json b/plugins/Cloudflare/v1/dataStreams/streamMinutesViewed.json new file mode 100644 index 00000000..2ad823cd --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/streamMinutesViewed.json @@ -0,0 +1,49 @@ +{ + "name": "streamMinutesViewed", + "displayName": "Stream Minutes Viewed", + "description": "Daily minutes of video viewed for a Cloudflare Stream video", + "tags": ["Media"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$uid:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){streamMinutesViewedAdaptiveGroups(limit:10000,filter:{uid:$uid,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){dimensions{date}sum{minutesViewed}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "uid": "{{object.rawId}}", + "start": "{{timeframe.start.split('T')[0]}}", + "end": "{{timeframe.end.split('T')[0]}}" + } + }, + "pathToData": "data.viewer.accounts.0.streamMinutesViewedAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare Stream Video"] + } + }, + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "sum.minutesViewed", + "displayName": "Minutes Viewed", + "shape": "minutes", + "role": "value" + } + ], + "timeframes": ["last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/streamVideos.json b/plugins/Cloudflare/v1/dataStreams/streamVideos.json new file mode 100644 index 00000000..5056f65a --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/streamVideos.json @@ -0,0 +1,90 @@ +{ + "name": "streamVideos", + "displayName": "Stream Videos", + "description": "Cloudflare Stream videos in an account with their processing state and duration", + "tags": [ + "Media" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/stream", + "postRequestScript": "streamVideos.js", + "paging": { + "mode": "none" + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "videoName", + "displayName": "Video", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare Stream Video" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "statusState", + "displayName": "State", + "shape": "string" + }, + { + "name": "duration", + "displayName": "Duration", + "shape": "seconds" + }, + { + "name": "size", + "displayName": "Size", + "shape": "bytes" + }, + { + "name": "readyToStream", + "displayName": "Ready", + "shape": "boolean" + }, + { + "name": "createdOn", + "displayName": "Created", + "shape": "date" + }, + { + "name": "preview", + "displayName": "Preview", + "shape": [ + "url", + { + "label": "Preview" + } + ] + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/turnstileChallenges.json b/plugins/Cloudflare/v1/dataStreams/turnstileChallenges.json new file mode 100644 index 00000000..2bbfb144 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/turnstileChallenges.json @@ -0,0 +1,63 @@ +{ + "name": "turnstileChallenges", + "displayName": "Turnstile Challenges", + "description": "Turnstile challenge counts for a widget grouped by a selectable dimension", + "tags": ["Security"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($accountTag:string!,$siteKey:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){turnstileAdaptiveGroups(limit:5000,filter:{siteKey:$siteKey,datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count dimensions{date {{breakdown}}}}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "siteKey": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "turnstileChallenges.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Turnstile Widget"] } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "eventType", + "options": [ + { "value": "eventType", "label": "Event Type" }, + { "value": "action", "label": "Action" } + ] + } + ], + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "challenges", + "displayName": "Challenges", + "shape": "number", + "role": "value" + } + ], + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/turnstileWidgets.json b/plugins/Cloudflare/v1/dataStreams/turnstileWidgets.json new file mode 100644 index 00000000..e3b86cc0 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/turnstileWidgets.json @@ -0,0 +1,85 @@ +{ + "name": "turnstileWidgets", + "displayName": "Turnstile Widgets", + "description": "Turnstile widgets configured in an account with their mode and domains", + "tags": [ + "Security" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "accounts/{{object.rawId}}/challenges/widgets", + "postRequestScript": "turnstileWidgets.js", + "paging": { + "mode": "none" + }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "visibility": { + "type": "hidden" + }, + "metadata": [ + { + "name": "sourceId", + "displayName": "Source ID", + "shape": "string", + "role": "id" + }, + { + "name": "widgetName", + "displayName": "Widget", + "shape": "string", + "role": "label", + "sourceId": "sourceId", + "sourceType": "Cloudflare Turnstile Widget" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "mode", + "displayName": "Mode", + "shape": "string" + }, + { + "name": "region", + "displayName": "Region", + "shape": "string" + }, + { + "name": "domains", + "displayName": "Domains", + "shape": "string" + }, + { + "name": "botFightMode", + "displayName": "Bot Fight Mode", + "shape": "boolean" + }, + { + "name": "createdOn", + "displayName": "Created", + "shape": "date" + }, + { + "name": "modifiedOn", + "displayName": "Modified", + "shape": "date" + } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v1/dataStreams/zoneHealthCheckEvents.json b/plugins/Cloudflare/v1/dataStreams/zoneHealthCheckEvents.json new file mode 100644 index 00000000..aa04d660 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/zoneHealthCheckEvents.json @@ -0,0 +1,87 @@ +{ + "name": "zoneHealthCheckEvents", + "displayName": "Health Check Events", + "description": "Individual health check pass/fail events for a zone, with origin, region and latency detail", + "tags": ["Zone", "Availability"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){healthCheckEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){count avg{rttMs}dimensions{datetime healthCheckName healthCheckId healthStatus healthChanged failureReason region originIP}}}}}", + "variables": { + "zoneTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "pathToData": "data.viewer.zones.0.healthCheckEventsAdaptiveGroups", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "dimensions.healthCheckName", + "displayName": "Health Check", + "shape": "string", + "role": "label" + }, + { + "name": "dimensions.healthStatus", + "displayName": "Status", + "shape": "string" + }, + { + "name": "dimensions.healthChanged", + "displayName": "Status Changed", + "shape": "number" + }, + { + "name": "dimensions.failureReason", + "displayName": "Failure Reason", + "shape": "string" + }, + { + "name": "dimensions.region", + "displayName": "Region", + "shape": "string" + }, + { + "name": "dimensions.originIP", + "displayName": "Origin IP", + "shape": "string" + }, + { + "name": "count", + "displayName": "Event Count", + "shape": "number", + "role": "value" + }, + { + "name": "avg.rttMs", + "displayName": "Avg Round Trip Time", + "shape": "milliseconds" + }, + { + "name": "dimensions.healthCheckId", + "displayName": "Health Check ID", + "shape": "string", + "visible": false + } + ], + "timeframes": ["last1hour", "last12hours", "last24hours"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/zoneNelReports.json b/plugins/Cloudflare/v1/dataStreams/zoneNelReports.json new file mode 100644 index 00000000..a8746d0c --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/zoneNelReports.json @@ -0,0 +1,64 @@ +{ + "name": "zoneNelReports", + "displayName": "Network Error Logs", + "description": "Browser-reported network errors for a zone grouped by a selectable dimension", + "tags": ["Zone", "Availability"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){nelReportsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count dimensions{date {{breakdown}}}}}}}", + "variables": { + "zoneTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "zoneNelReports.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "type", + "options": [ + { "value": "type", "label": "Error Type" }, + { "value": "phase", "label": "Phase" }, + { "value": "clientIPCountry", "label": "Country" }, + { "value": "lastKnownGoodColoCode", "label": "Edge Location" } + ] + } + ], + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "events", + "displayName": "Events", + "shape": "number", + "role": "value" + } + ], + "timeframes": ["last24hours", "last7days"] +} diff --git a/plugins/Cloudflare/v1/dataStreams/zonePageShield.json b/plugins/Cloudflare/v1/dataStreams/zonePageShield.json new file mode 100644 index 00000000..3f7d91d9 --- /dev/null +++ b/plugins/Cloudflare/v1/dataStreams/zonePageShield.json @@ -0,0 +1,64 @@ +{ + "name": "zonePageShield", + "displayName": "Page Shield Reports", + "description": "Page Shield script and connection monitoring events for a zone grouped by a selectable dimension", + "tags": ["Zone", "Security"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){pageShieldReportsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count dimensions{date {{breakdown}}}}}}}", + "variables": { + "zoneTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "zonePageShield.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "resourceType", + "options": [ + { "value": "resourceType", "label": "Resource Type" }, + { "value": "urlHost", "label": "Resource Host" }, + { "value": "cspDirective", "label": "CSP Directive" }, + { "value": "action", "label": "Action" } + ] + } + ], + "metadata": [ + { + "name": "date", + "displayName": "Date", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "events", + "displayName": "Events", + "shape": "number", + "role": "value" + } + ], + "timeframes": ["last24hours", "last7days"] +} diff --git a/plugins/Cloudflare/v1/defaultContent/AI/aiGateway.dash.json b/plugins/Cloudflare/v1/defaultContent/AI/aiGateway.dash.json new file mode 100644 index 00000000..47e6b31c --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/AI/aiGateway.dash.json @@ -0,0 +1,830 @@ +{ + "name": "AI Gateway", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": [ + "{{variables.[Cloudflare AI Gateway]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "750b8a80-1d88-4579-87de-53c872f78d7d", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[aiGatewayRequests]}}", + "name": "aiGatewayRequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "model" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AI Gateways]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AI Gateway]}}" + }, + "variables": [ + "{{variables.[Cloudflare AI Gateway]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count_sum", + "comparisonColumn": "none", + "label": "Requests" + } + } + } + } + }, + { + "i": "83e8fc2c-7fc7-4e76-99d7-d696efb05946", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[aiGatewayRequests]}}", + "name": "aiGatewayRequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "model" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.totalTokens" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AI Gateways]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AI Gateway]}}" + }, + "variables": [ + "{{variables.[Cloudflare AI Gateway]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.totalTokens_sum", + "comparisonColumn": "none", + "label": "Total Tokens" + } + } + } + } + }, + { + "i": "3f547967-d776-4c34-aede-977429b6bc1c", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[aiGatewayRequests]}}", + "name": "aiGatewayRequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "model" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.cost" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AI Gateways]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AI Gateway]}}" + }, + "variables": [ + "{{variables.[Cloudflare AI Gateway]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.cost_sum", + "comparisonColumn": "none", + "label": "Cost" + } + } + } + } + }, + { + "i": "9014c501-a75a-47ca-ad4c-9248b8900e74", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[aiGatewayErrors]}}", + "name": "aiGatewayErrors", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "model" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AI Gateways]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AI Gateway]}}" + }, + "variables": [ + "{{variables.[Cloudflare AI Gateway]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count_sum", + "comparisonColumn": "none", + "label": "Errors" + } + } + } + } + }, + { + "i": "d04df137-5984-4f36-869e-24b826dbda12", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Gateway Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare AI Gateways]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AI Gateway]}}" + }, + "variables": [ + "{{variables.[Cloudflare AI Gateway]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "596b3e4e-5047-4106-8ba3-6214968a0092", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Requests Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[aiGatewayRequests]}}", + "name": "aiGatewayRequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "model" + }, + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AI Gateways]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AI Gateway]}}" + }, + "variables": [ + "{{variables.[Cloudflare AI Gateway]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "count_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "804101b6-6e18-4bde-a722-85704e429865", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Requests by Model", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[aiGatewayRequests]}}", + "name": "aiGatewayRequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "model" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AI Gateways]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AI Gateway]}}" + }, + "variables": [ + "{{variables.[Cloudflare AI Gateway]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "count_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "d4b539e2-5477-4a17-a133-c594e0218ebc", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Requests by Provider", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[aiGatewayRequests]}}", + "name": "aiGatewayRequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "provider" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AI Gateways]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AI Gateway]}}" + }, + "variables": [ + "{{variables.[Cloudflare AI Gateway]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "c54a8c5c-6710-45ff-a7c4-ca9855b11a38", + "x": 0, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Token Usage", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[aiGatewayRequests]}}", + "name": "aiGatewayRequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "model" + }, + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.tokensIn" + ] + }, + { + "type": "sum", + "names": [ + "sum.tokensOut" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AI Gateways]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AI Gateway]}}" + }, + "variables": [ + "{{variables.[Cloudflare AI Gateway]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "sum.tokensIn_sum", + "sum.tokensOut_sum" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "da515089-5536-40dc-a44d-8e01c9f9a720", + "x": 2, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Request Duration Percentiles", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[aiGatewayRequests]}}", + "name": "aiGatewayRequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "model" + }, + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "quantiles.durationMsP50" + ] + }, + { + "type": "mean", + "names": [ + "quantiles.durationMsP95" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AI Gateways]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AI Gateway]}}" + }, + "variables": [ + "{{variables.[Cloudflare AI Gateway]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "quantiles.durationMsP50_mean", + "quantiles.durationMsP95_mean" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "3623cdf1-bff6-4d83-96af-d1a77db0d783", + "x": 0, + "y": 11, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Errors by Model", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[aiGatewayErrors]}}", + "name": "aiGatewayErrors", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "model" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AI Gateways]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AI Gateway]}}" + }, + "variables": [ + "{{variables.[Cloudflare AI Gateway]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "count_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "3f461a5f-7623-44f1-8970-284b111aa2f3", + "x": 2, + "y": 11, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Cache Status", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[aiGatewayCache]}}", + "name": "aiGatewayCache", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "cacheStatus", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AI Gateways]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AI Gateway]}}" + }, + "variables": [ + "{{variables.[Cloudflare AI Gateway]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count_sum", + "labelColumn": "cacheStatus_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/AI/autorag.dash.json b/plugins/Cloudflare/v1/defaultContent/AI/autorag.dash.json new file mode 100644 index 00000000..bbc234a3 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/AI/autorag.dash.json @@ -0,0 +1,595 @@ +{ + "name": "AutoRAG", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": [ + "{{variables.[Cloudflare AutoRAG]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "36c46ca5-8a89-4987-9a1a-494b88743857", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[autoragQueries]}}", + "name": "autoragQueries", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "searchType" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AutoRAGs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AutoRAG]}}" + }, + "variables": [ + "{{variables.[Cloudflare AutoRAG]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count_sum", + "comparisonColumn": "none", + "label": "Search Events" + } + } + } + } + }, + { + "i": "9531a84a-921d-4920-b327-7c408cf980c4", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[autoragQueries]}}", + "name": "autoragQueries", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "searchType" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.aiSearchCount" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AutoRAGs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AutoRAG]}}" + }, + "variables": [ + "{{variables.[Cloudflare AutoRAG]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.aiSearchCount_sum", + "comparisonColumn": "none", + "label": "AI Searches" + } + } + } + } + }, + { + "i": "3d2a39c2-64de-4fe8-9669-b6da7ece7062", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[autoragQueries]}}", + "name": "autoragQueries", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "searchType" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.searchCount" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AutoRAGs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AutoRAG]}}" + }, + "variables": [ + "{{variables.[Cloudflare AutoRAG]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.searchCount_sum", + "comparisonColumn": "none", + "label": "Searches" + } + } + } + } + }, + { + "i": "2c2c7223-38f1-4895-9c89-86c1139991f5", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[autoragQueries]}}", + "name": "autoragQueries", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "embeddingModel" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "distinctCount", + "names": [ + "breakdown" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AutoRAGs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AutoRAG]}}" + }, + "variables": [ + "{{variables.[Cloudflare AutoRAG]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "breakdown_distinctCount", + "comparisonColumn": "none", + "label": "Embedding Models" + } + } + } + } + }, + { + "i": "77ebd440-1d19-4eb4-9984-0d2f45525a77", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "AutoRAG Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare AutoRAGs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AutoRAG]}}" + }, + "variables": [ + "{{variables.[Cloudflare AutoRAG]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "58851ad7-7a43-4494-ac09-dbb9f32a22be", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Queries Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[autoragQueries]}}", + "name": "autoragQueries", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "searchType" + }, + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AutoRAGs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AutoRAG]}}" + }, + "variables": [ + "{{variables.[Cloudflare AutoRAG]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "count_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "912ec506-a20c-40ca-aa18-dabdb216190d", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Queries by Search Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[autoragQueries]}}", + "name": "autoragQueries", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "searchType" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AutoRAGs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AutoRAG]}}" + }, + "variables": [ + "{{variables.[Cloudflare AutoRAG]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "9631c0b4-694a-4f1c-9344-b12bedfd19bc", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Queries by Embedding Model", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[autoragQueries]}}", + "name": "autoragQueries", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "embeddingModel" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AutoRAGs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AutoRAG]}}" + }, + "variables": [ + "{{variables.[Cloudflare AutoRAG]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "count_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "1a9bb402-64cb-41de-bbf9-e68dc8b2ce59", + "x": 0, + "y": 8, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "AI Searches and Searches Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[autoragQueries]}}", + "name": "autoragQueries", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "searchType" + }, + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.aiSearchCount" + ] + }, + { + "type": "sum", + "names": [ + "sum.searchCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare AutoRAGs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare AutoRAG]}}" + }, + "variables": [ + "{{variables.[Cloudflare AutoRAG]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "sum.aiSearchCount_sum", + "sum.searchCount_sum" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/AI/manifest.json b/plugins/Cloudflare/v1/defaultContent/AI/manifest.json new file mode 100644 index 00000000..caf9ab6f --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/AI/manifest.json @@ -0,0 +1,16 @@ +{ + "items": [ + { + "name": "vectorizeIndex", + "type": "dashboard" + }, + { + "name": "aiGateway", + "type": "dashboard" + }, + { + "name": "autorag", + "type": "dashboard" + } + ] +} diff --git a/plugins/Cloudflare/v1/defaultContent/vectorizeIndex.dash.json b/plugins/Cloudflare/v1/defaultContent/AI/vectorizeIndex.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/vectorizeIndex.dash.json rename to plugins/Cloudflare/v1/defaultContent/AI/vectorizeIndex.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Compute/containerApplication.dash.json b/plugins/Cloudflare/v1/defaultContent/Compute/containerApplication.dash.json new file mode 100644 index 00000000..730ef301 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/Compute/containerApplication.dash.json @@ -0,0 +1,669 @@ +{ + "name": "Container Application", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": [ + "{{variables.[Cloudflare Container Application]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "e64676a0-67f4-4630-834f-d501d77c507f", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[containerMetrics]}}", + "name": "containerMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "region" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "mean", + "names": [ + "avgCpuUtilization" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Container Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Container Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Container Application]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "avgCpuUtilization_mean", + "comparisonColumn": "none", + "label": "Avg CPU Utilization" + } + } + } + } + }, + { + "i": "dfa0e14c-6d1a-4fe6-b721-ef8744d09608", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[containerMetrics]}}", + "name": "containerMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "region" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "mean", + "names": [ + "avgMemory" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Container Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Container Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Container Application]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "avgMemory_mean", + "comparisonColumn": "none", + "label": "Avg Memory Usage" + } + } + } + } + }, + { + "i": "426c6724-0bf9-4f84-abd8-e2a64c6e637e", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[containerMetrics]}}", + "name": "containerMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "region" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sumRxBytes" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Container Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Container Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Container Application]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sumRxBytes_sum", + "comparisonColumn": "none", + "label": "Bytes Received" + } + } + } + } + }, + { + "i": "63b496af-5b0f-449a-9d42-86878b20ae2f", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[containerMetrics]}}", + "name": "containerMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "region" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sumTxBytes" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Container Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Container Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Container Application]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sumTxBytes_sum", + "comparisonColumn": "none", + "label": "Bytes Transmitted" + } + } + } + } + }, + { + "i": "badc57c3-fbc9-4562-85ab-b338812f1db9", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Application Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Container Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Container Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Container Application]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "99aa195b-b61b-4203-bcbb-80986a924f73", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "CPU Utilization Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[containerMetrics]}}", + "name": "containerMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "region" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "avgCpuUtilization" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Container Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Container Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Container Application]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "avgCpuUtilization_mean" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "0bbdce17-1f27-4899-9aa5-75c3ac58e6d0", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Memory Usage Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[containerMetrics]}}", + "name": "containerMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "region" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "avgMemory" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Container Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Container Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Container Application]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "avgMemory_mean" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "25402b1b-0bff-4143-8458-785b85d4adbb", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Network Traffic", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[containerMetrics]}}", + "name": "containerMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "region" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sumRxBytes" + ] + }, + { + "type": "sum", + "names": [ + "sumTxBytes" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Container Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Container Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Container Application]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "sumRxBytes_sum", + "sumTxBytes_sum" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "7128c134-17ab-4263-8885-971edabba81f", + "x": 0, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "CPU Utilization by Region", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[containerMetrics]}}", + "name": "containerMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "region" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "avgCpuUtilization" + ] + } + ] + }, + "sort": { + "by": [ + [ + "avgCpuUtilization_mean", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Container Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Container Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Container Application]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "avgCpuUtilization_mean" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "2d8456d9-65a9-4c19-83ec-86806c99a217", + "x": 2, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Samples by Process Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[containerMetrics]}}", + "name": "containerMetrics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "procType" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Container Applications]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Container Application]}}" + }, + "variables": [ + "{{variables.[Cloudflare Container Application]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/durableObjectNamespace.dash.json b/plugins/Cloudflare/v1/defaultContent/Compute/durableObjectNamespace.dash.json similarity index 88% rename from plugins/Cloudflare/v1/defaultContent/durableObjectNamespace.dash.json rename to plugins/Cloudflare/v1/defaultContent/Compute/durableObjectNamespace.dash.json index d373680f..97df92e0 100644 --- a/plugins/Cloudflare/v1/defaultContent/durableObjectNamespace.dash.json +++ b/plugins/Cloudflare/v1/defaultContent/Compute/durableObjectNamespace.dash.json @@ -568,6 +568,77 @@ } } } + }, + { + "i": "502b9595-01fe-4ec7-a24b-cd6e47c44225", + "x": 0, + "y": 11, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Uncached Subrequest Body Size", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[durableObjectSubrequests]}}", + "name": "durableObjectSubrequests", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetime", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requestBodySizeUncached" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.datetime_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Durable Object Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare Durable Object Namespace]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byDay", + "yAxisColumn": [ + "sum.requestBodySizeUncached_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } } ] } diff --git a/plugins/Cloudflare/v1/defaultContent/Compute/manifest.json b/plugins/Cloudflare/v1/defaultContent/Compute/manifest.json new file mode 100644 index 00000000..e3e17018 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/Compute/manifest.json @@ -0,0 +1,28 @@ +{ + "items": [ + { + "name": "worker", + "type": "dashboard" + }, + { + "name": "pagesProject", + "type": "dashboard" + }, + { + "name": "durableObjectNamespace", + "type": "dashboard" + }, + { + "name": "queue", + "type": "dashboard" + }, + { + "name": "containerApplication", + "type": "dashboard" + }, + { + "name": "pipeline", + "type": "dashboard" + } + ] +} diff --git a/plugins/Cloudflare/v1/defaultContent/pagesProject.dash.json b/plugins/Cloudflare/v1/defaultContent/Compute/pagesProject.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/pagesProject.dash.json rename to plugins/Cloudflare/v1/defaultContent/Compute/pagesProject.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Compute/pipeline.dash.json b/plugins/Cloudflare/v1/defaultContent/Compute/pipeline.dash.json new file mode 100644 index 00000000..311c1a86 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/Compute/pipeline.dash.json @@ -0,0 +1,484 @@ +{ + "name": "Pipeline", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": [ + "{{variables.[Cloudflare Pipeline]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "2d40ce01-f6ee-42df-acb1-5d371a8ff3d9", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pipelineIngestion]}}", + "name": "pipelineIngestion", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.ingestedRecords" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Pipelines]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Pipeline]}}" + }, + "variables": [ + "{{variables.[Cloudflare Pipeline]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.ingestedRecords_sum", + "comparisonColumn": "none", + "label": "Records Ingested" + } + } + } + } + }, + { + "i": "8aa7942a-4ce0-477b-90b1-d382bd2bb275", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pipelineIngestion]}}", + "name": "pipelineIngestion", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.ingestedBytes" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Pipelines]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Pipeline]}}" + }, + "variables": [ + "{{variables.[Cloudflare Pipeline]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.ingestedBytes_sum", + "comparisonColumn": "none", + "label": "Bytes Ingested" + } + } + } + } + }, + { + "i": "e2bbd68e-ebfc-4bde-800a-47e740c262c8", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pipelineIngestion]}}", + "name": "pipelineIngestion", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Pipelines]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Pipeline]}}" + }, + "variables": [ + "{{variables.[Cloudflare Pipeline]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count_sum", + "comparisonColumn": "none", + "label": "Ingestion Operations" + } + } + } + } + }, + { + "i": "a079e54c-c4d7-4236-8483-94ecdf0ac8b6", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pipelineIngestion]}}", + "name": "pipelineIngestion", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "max", + "names": [ + "sum.ingestedRecords" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Pipelines]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Pipeline]}}" + }, + "variables": [ + "{{variables.[Cloudflare Pipeline]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.ingestedRecords_max", + "comparisonColumn": "none", + "label": "Peak Daily Records" + } + } + } + } + }, + { + "i": "df863625-6b8f-44b4-8a64-c5018500637c", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Pipeline Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Pipelines]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Pipeline]}}" + }, + "variables": [ + "{{variables.[Cloudflare Pipeline]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "a0d7a2e9-ad48-4b53-8bc6-67a76630f405", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Records Ingested Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pipelineIngestion]}}", + "name": "pipelineIngestion", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.ingestedRecords" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Pipelines]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Pipeline]}}" + }, + "variables": [ + "{{variables.[Cloudflare Pipeline]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "sum.ingestedRecords_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "a5f002a3-649b-4dfe-bf12-de06f89826b8", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Bytes Ingested Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pipelineIngestion]}}", + "name": "pipelineIngestion", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.ingestedBytes" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Pipelines]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Pipeline]}}" + }, + "variables": [ + "{{variables.[Cloudflare Pipeline]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "sum.ingestedBytes_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "44658838-c03d-40a8-a720-a4d5fe42e078", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Ingestion Operations Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pipelineIngestion]}}", + "name": "pipelineIngestion", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Pipelines]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Pipeline]}}" + }, + "variables": [ + "{{variables.[Cloudflare Pipeline]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "count_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/queue.dash.json b/plugins/Cloudflare/v1/defaultContent/Compute/queue.dash.json similarity index 88% rename from plugins/Cloudflare/v1/defaultContent/queue.dash.json rename to plugins/Cloudflare/v1/defaultContent/Compute/queue.dash.json index 997c8dd2..a0c9d5b4 100644 --- a/plugins/Cloudflare/v1/defaultContent/queue.dash.json +++ b/plugins/Cloudflare/v1/defaultContent/Compute/queue.dash.json @@ -543,6 +543,77 @@ } } } + }, + { + "i": "496dac59-2c8d-41aa-a882-818cd6d36d70", + "x": 0, + "y": 11, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Consumer Concurrency", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[queueConsumerMetrics]}}", + "name": "queueConsumerMetrics", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetime", + "byHour" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "avg.concurrency" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.datetime_byHour", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Queues]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Queue]}}" + }, + "variables": [ + "{{variables.[Cloudflare Queue]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byHour", + "yAxisColumn": [ + "avg.concurrency_mean" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } } ] } diff --git a/plugins/Cloudflare/v1/defaultContent/worker.dash.json b/plugins/Cloudflare/v1/defaultContent/Compute/worker.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/worker.dash.json rename to plugins/Cloudflare/v1/defaultContent/Compute/worker.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/account.dash.json b/plugins/Cloudflare/v1/defaultContent/Core/account.dash.json similarity index 55% rename from plugins/Cloudflare/v1/defaultContent/account.dash.json rename to plugins/Cloudflare/v1/defaultContent/Core/account.dash.json index b26f672f..4de065a7 100644 --- a/plugins/Cloudflare/v1/defaultContent/account.dash.json +++ b/plugins/Cloudflare/v1/defaultContent/Core/account.dash.json @@ -787,9 +787,185 @@ } }, { - "i": "d7931877-849c-421d-88e5-c5a83d107ce4", + "i": "83f57d60-3e02-40dd-8ab5-9ca6bed4fea9", "x": 0, "y": 21, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Durable Object Namespaces", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[durableObjectNamespaces]}}", + "name": "durableObjectNamespaces", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "namespaceName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "namespaceName", + "scriptName", + "className", + "usesSqlite" + ], + "hiddenColumns": [ + "sourceId", + "accountId" + ] + } + } + } + } + }, + { + "i": "2336e698-182b-4dc7-83bf-5d104c88eead", + "x": 2, + "y": 21, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Vectorize Indexes", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[vectorizeIndexes]}}", + "name": "vectorizeIndexes", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "indexName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "indexName", + "dimensions", + "metric", + "createdOn" + ], + "hiddenColumns": [ + "sourceId", + "accountId", + "modifiedOn" + ] + } + } + } + } + }, + { + "i": "7c8fd8d9-542a-4665-9621-e7ed1b8583b7", + "x": 0, + "y": 25, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Hyperdrive Configs", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[hyperdriveConfigs]}}", + "name": "hyperdriveConfigs", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "configName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "configName", + "database", + "host", + "scheme" + ], + "hiddenColumns": [ + "sourceId", + "accountId", + "cachingDisabled" + ] + } + } + } + } + }, + { + "i": "d7931877-849c-421d-88e5-c5a83d107ce4", + "x": 0, + "y": 29, "w": 1, "h": 2, "moved": false, @@ -845,7 +1021,7 @@ { "i": "6d0c0f83-1c51-43b7-90f1-1ec4226b8d2a", "x": 1, - "y": 21, + "y": 29, "w": 1, "h": 2, "moved": false, @@ -901,7 +1077,7 @@ { "i": "0e7ae631-b894-4f67-a73a-b9e61ce540f9", "x": 2, - "y": 21, + "y": 29, "w": 1, "h": 2, "moved": false, @@ -957,7 +1133,7 @@ { "i": "685debee-fe22-4057-be74-f16010314596", "x": 3, - "y": 21, + "y": 29, "w": 1, "h": 2, "moved": false, @@ -1013,7 +1189,7 @@ { "i": "2edd6feb-b28c-455a-bb9b-8abdbbf04638", "x": 0, - "y": 23, + "y": 31, "w": 2, "h": 3, "moved": false, @@ -1086,7 +1262,7 @@ { "i": "fab0220c-a177-4a16-8d9b-a9bb5ebbd0fb", "x": 2, - "y": 23, + "y": 31, "w": 2, "h": 3, "moved": false, @@ -1173,7 +1349,7 @@ { "i": "daad39ca-4ae3-437e-a2a4-657f660e6045", "x": 0, - "y": 26, + "y": 34, "w": 2, "h": 3, "moved": false, @@ -1246,7 +1422,7 @@ { "i": "7fe5da45-cb35-4c2b-98db-58e08a5bbbcd", "x": 2, - "y": 26, + "y": 34, "w": 2, "h": 3, "moved": false, @@ -1331,51 +1507,38 @@ } }, { - "i": "cb3540f5-b6f5-4596-9555-b9ee9a2b8792", + "i": "ac748a4a-ca7b-4b10-a2c0-50936b00e9d7", "x": 0, - "y": 29, - "w": 2, - "h": 3, + "y": 37, + "w": 1, + "h": 2, "moved": false, "static": false, "z": 0, "config": { "_type": "tile/data-stream", - "title": "Gateway HTTP Requests Over Time", + "title": "", "description": "", "activePluginConfigIds": [ "{{configId}}" ], "dataStream": { - "id": "{{dataStreams.[gatewayHttpRequests]}}", - "name": "gatewayHttpRequests", + "id": "{{dataStreams.[gatewayNetworkSessions]}}", + "name": "gatewayNetworkSessions", "pluginConfigId": "{{configId}}", "dataSourceConfig": { "breakdown": "action" }, "group": { - "by": [ - [ - "date", - "byDay" - ] - ], + "by": [], "aggregate": [ { "type": "sum", "names": [ - "requests" + "sessionCount" ] } ] - }, - "sort": { - "by": [ - [ - "date_byDay", - "asc" - ] - ] } }, "timeframe": "last7days", @@ -1388,27 +1551,21 @@ "{{variables.[Cloudflare Account]}}" ], "visualisation": { - "type": "data-stream-line-graph", + "type": "data-stream-scalar", "config": { - "data-stream-line-graph": { - "xAxisColumn": "date_byDay", - "yAxisColumn": [ - "requests_sum" - ], - "seriesColumn": "none", - "showLegend": false, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false + "data-stream-scalar": { + "value": "sessionCount_sum", + "comparisonColumn": "none", + "label": "Gateway Network Sessions" } } } } }, { - "i": "6ebe2742-9444-4be7-9edc-1c5b1e113633", - "x": 2, - "y": 29, + "i": "ae5e51c8-183b-4518-958e-422eafc1779e", + "x": 0, + "y": 39, "w": 2, "h": 3, "moved": false, @@ -1416,17 +1573,17 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "Workers AI Requests by Model", + "title": "Gateway Network Sessions by Action", "description": "", "activePluginConfigIds": [ "{{configId}}" ], "dataStream": { - "id": "{{dataStreams.[workersAiInference]}}", - "name": "workersAiInference", + "id": "{{dataStreams.[gatewayNetworkSessions]}}", + "name": "gatewayNetworkSessions", "pluginConfigId": "{{configId}}", "dataSourceConfig": { - "breakdown": "modelId" + "breakdown": "action" }, "group": { "by": [ @@ -1439,7 +1596,7 @@ { "type": "sum", "names": [ - "requests" + "sessionCount" ] } ] @@ -1447,7 +1604,7 @@ "sort": { "by": [ [ - "requests_sum", + "sessionCount_sum", "desc" ] ], @@ -1464,38 +1621,24 @@ "{{variables.[Cloudflare Account]}}" ], "visualisation": { - "type": "data-stream-bar-chart", + "type": "data-stream-donut-chart", "config": { - "data-stream-bar-chart": { - "xAxisData": "breakdown_uniqueValues", - "yAxisData": [ - "requests_sum" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "vertical", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } + "data-stream-donut-chart": { + "valueColumn": "sessionCount_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" } } } } }, { - "i": "e3b25cc5-489a-4604-96ce-d49e3ee5b6e6", + "i": "cb3540f5-b6f5-4596-9555-b9ee9a2b8792", "x": 0, - "y": 32, + "y": 42, "w": 2, "h": 3, "moved": false, @@ -1503,17 +1646,17 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "Workers AI Token Usage", + "title": "Gateway HTTP Requests Over Time", "description": "", "activePluginConfigIds": [ "{{configId}}" ], "dataStream": { - "id": "{{dataStreams.[workersAiInference]}}", - "name": "workersAiInference", + "id": "{{dataStreams.[gatewayHttpRequests]}}", + "name": "gatewayHttpRequests", "pluginConfigId": "{{configId}}", "dataSourceConfig": { - "breakdown": "modelId" + "breakdown": "action" }, "group": { "by": [ @@ -1526,13 +1669,7 @@ { "type": "sum", "names": [ - "inputTokens" - ] - }, - { - "type": "sum", - "names": [ - "outputTokens" + "requests" ] } ] @@ -1561,7 +1698,175 @@ "data-stream-line-graph": { "xAxisColumn": "date_byDay", "yAxisColumn": [ - "inputTokens_sum", + "requests_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "6ebe2742-9444-4be7-9edc-1c5b1e113633", + "x": 2, + "y": 42, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Workers AI Requests by Model", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workersAiInference]}}", + "name": "workersAiInference", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "modelId" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "requests_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "requests_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "e3b25cc5-489a-4604-96ce-d49e3ee5b6e6", + "x": 0, + "y": 45, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Workers AI Token Usage", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workersAiInference]}}", + "name": "workersAiInference", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "modelId" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "inputTokens" + ] + }, + { + "type": "sum", + "names": [ + "outputTokens" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "inputTokens_sum", "outputTokens_sum" ], "seriesColumn": "none", @@ -1577,7 +1882,7 @@ { "i": "2d7e5b1b-394e-4111-91de-2aa319f7fea8", "x": 2, - "y": 32, + "y": 45, "w": 2, "h": 3, "moved": false, @@ -1648,6 +1953,999 @@ } } } + }, + { + "i": "a38a89d8-b533-4bef-bbbb-3bfefb3f44ba", + "x": 0, + "y": 48, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[auditLogs]}}", + "name": "auditLogs", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "actionType" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "actionCount" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "actionCount_sum", + "comparisonColumn": "none", + "label": "Audit Log Actions" + } + } + } + } + }, + { + "i": "885088db-eba0-4a67-a170-c12c84b61c3c", + "x": 1, + "y": 48, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[imagesRequests]}}", + "name": "imagesRequests", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "requests_sum", + "comparisonColumn": "none", + "label": "Image Requests" + } + } + } + } + }, + { + "i": "33b7c30d-8dea-42a1-96d8-a885c9119f0a", + "x": 2, + "y": 48, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[imagesTransformations]}}", + "name": "imagesTransformations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "transformations" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "transformations_sum", + "comparisonColumn": "none", + "label": "Image Transformations" + } + } + } + } + }, + { + "i": "b6731e3d-91a3-4ead-9685-7df79e235ce0", + "x": 3, + "y": 48, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pagesFunctionsInvocations]}}", + "name": "pagesFunctionsInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.requests_sum", + "comparisonColumn": "none", + "label": "Pages Function Requests" + } + } + } + } + }, + { + "i": "463aafc7-e7fe-483a-9415-135d591794ab", + "x": 0, + "y": 50, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Audit Log Actions Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[auditLogs]}}", + "name": "auditLogs", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "actionType" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "actionCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "actionCount_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "b674edbe-1b30-41b5-a4fa-08bf7ad4ffb5", + "x": 2, + "y": 50, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Top Audit Log Actions", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[auditLogs]}}", + "name": "auditLogs", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "actionType" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "actionCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "actionCount_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "actionCount_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "ed67a1f0-321c-48e0-98da-937932cbe709", + "x": 0, + "y": 53, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Image Requests Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[imagesRequests]}}", + "name": "imagesRequests", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "requests_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "f1b12eaa-907d-4268-8481-fad2f24f707a", + "x": 2, + "y": 53, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Image Transformations Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[imagesTransformations]}}", + "name": "imagesTransformations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "transformations" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "transformations_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "a43ecf79-6372-4f65-bec5-d9e8c925d643", + "x": 0, + "y": 56, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Pages Functions Requests and Errors", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pagesFunctionsInvocations]}}", + "name": "pagesFunctionsInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetime", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + }, + { + "type": "sum", + "names": [ + "sum.errors" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.datetime_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byDay", + "yAxisColumn": [ + "sum.requests_sum", + "sum.errors_sum" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "76b7293c-87ef-41eb-97c3-3633f59732de", + "x": 2, + "y": 56, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Top Pages Functions by Requests", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pagesFunctionsInvocations]}}", + "name": "pagesFunctionsInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.scriptName", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "sum.requests_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "dimensions.scriptName_uniqueValues", + "yAxisData": [ + "sum.requests_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "18fdde70-9cd8-4d1b-8b5c-0b06ccd397cd", + "x": 0, + "y": 59, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Browser Rendering Session Duration", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[browserRendering]}}", + "name": "browserRendering", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "clientLibrary" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "durationMs" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "durationMs_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "b7a3742d-41bb-42f0-8588-22ae18ba6cc3", + "x": 2, + "y": 59, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Browser Rendering Sessions by Client Library", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[browserRendering]}}", + "name": "browserRendering", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "clientLibrary" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "distinctCount", + "names": [ + "sessionId" + ] + } + ] + }, + "sort": { + "by": [ + [ + "sessionId_distinctCount", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "sessionId_distinctCount" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "36b11ab5-9da0-456f-8056-cfb27f386542", + "x": 0, + "y": 62, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "DNS Firewall Queries Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[dnsFirewallAnalytics]}}", + "name": "dnsFirewallAnalytics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "responseCode" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "queries" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "queries_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "876b9baa-c52d-4f4a-8cdd-8f8d5d490a58", + "x": 2, + "y": 62, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "DNS Firewall Queries by Response Code", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[dnsFirewallAnalytics]}}", + "name": "dnsFirewallAnalytics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "responseCode" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "queries" + ] + } + ] + }, + "sort": { + "by": [ + [ + "queries_sum", + "desc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "queries_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } } ] } diff --git a/plugins/Cloudflare/v1/defaultContent/Core/manifest.json b/plugins/Cloudflare/v1/defaultContent/Core/manifest.json new file mode 100644 index 00000000..7b59b59d --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/Core/manifest.json @@ -0,0 +1,12 @@ +{ + "items": [ + { + "name": "account", + "type": "dashboard" + }, + { + "name": "zone", + "type": "dashboard" + } + ] +} diff --git a/plugins/Cloudflare/v1/defaultContent/zone.dash.json b/plugins/Cloudflare/v1/defaultContent/Core/zone.dash.json similarity index 74% rename from plugins/Cloudflare/v1/defaultContent/zone.dash.json rename to plugins/Cloudflare/v1/defaultContent/Core/zone.dash.json index e4a27927..208ccc8a 100644 --- a/plugins/Cloudflare/v1/defaultContent/zone.dash.json +++ b/plugins/Cloudflare/v1/defaultContent/Core/zone.dash.json @@ -2252,6 +2252,754 @@ } } } + }, + { + "i": "5a35c781-2682-4880-bff7-77c61d52ae5f", + "x": 0, + "y": 48, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Email Routing Messages by Action", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[emailRouting]}}", + "name": "emailRouting", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "action" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "messageCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "messageCount_sum", + "desc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "messageCount_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "e7ec1705-838a-4d37-918b-496b4da2e138", + "x": 2, + "y": 48, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Email Routing Messages Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[emailRouting]}}", + "name": "emailRouting", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "status" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "messageCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "messageCount_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "404f3e25-56a7-4f0d-b112-e9c12846d0bb", + "x": 0, + "y": 51, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "DMARC Messages by Disposition", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[dmarcReports]}}", + "name": "dmarcReports", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "disposition" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "messageCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "messageCount_sum", + "desc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "messageCount_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "f741cb88-09ec-49d5-afac-2e55358ec1c9", + "x": 2, + "y": 51, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Top DMARC Sending Organizations", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[dmarcReports]}}", + "name": "dmarcReports", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "sourceOrgName" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "messageCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "messageCount_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "messageCount_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "d2d06e16-5181-4c42-9faf-f5eb6986072f", + "x": 0, + "y": 54, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Cache Reserve Operations by Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[cacheReserveOperations]}}", + "name": "cacheReserveOperations", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "operationClass" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "operationCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "operationCount_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "operationCount_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "2072f98c-365b-4001-9594-eed5b5612479", + "x": 2, + "y": 54, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Cache Reserve Storage", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[cacheReserveStorage]}}", + "name": "cacheReserveStorage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetime", + "byHour" + ] + ], + "aggregate": [ + { + "type": "max", + "names": [ + "max.storedBytes" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.datetime_byHour", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byHour", + "yAxisColumn": [ + "max.storedBytes_max" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "d1d83606-df02-4ee0-88ad-4b88401340ad", + "x": 0, + "y": 57, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Health Check Events by Status", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneHealthCheckEvents]}}", + "name": "zoneHealthCheckEvents", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.healthStatus", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ] + } + }, + "timeframe": "last24hours", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count_sum", + "labelColumn": "dimensions.healthStatus_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "18a14576-aa42-440d-8f32-28024ebb0003", + "x": 2, + "y": 57, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Health Check Round Trip Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneHealthCheckEvents]}}", + "name": "zoneHealthCheckEvents", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetime", + "byHour" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "avg.rttMs" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.datetime_byHour", + "asc" + ] + ] + } + }, + "timeframe": "last24hours", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byHour", + "yAxisColumn": [ + "avg.rttMs_mean" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "0b37e21b-6c6a-4442-8a58-507f77fb6451", + "x": 0, + "y": 60, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Network Error Logging by Error Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneNelReports]}}", + "name": "zoneNelReports", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "type" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "events" + ] + } + ] + }, + "sort": { + "by": [ + [ + "events_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "events_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "60c857c2-28a9-47cf-b0aa-85676a291c9f", + "x": 2, + "y": 60, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Page Shield Events by Resource Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zonePageShield]}}", + "name": "zonePageShield", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "resourceType" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "events" + ] + } + ] + }, + "sort": { + "by": [ + [ + "events_sum", + "desc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "events_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } } ] } diff --git a/plugins/Cloudflare/v1/defaultContent/Media/manifest.json b/plugins/Cloudflare/v1/defaultContent/Media/manifest.json new file mode 100644 index 00000000..4a18653d --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/Media/manifest.json @@ -0,0 +1,12 @@ +{ + "items": [ + { + "name": "streamVideo", + "type": "dashboard" + }, + { + "name": "realtimeApp", + "type": "dashboard" + } + ] +} diff --git a/plugins/Cloudflare/v1/defaultContent/Media/realtimeApp.dash.json b/plugins/Cloudflare/v1/defaultContent/Media/realtimeApp.dash.json new file mode 100644 index 00000000..76523d73 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/Media/realtimeApp.dash.json @@ -0,0 +1,500 @@ +{ + "name": "Realtime App", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": [ + "{{variables.[Cloudflare Realtime App]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "5b09fae2-8a34-4207-b2f9-e086b11a9bda", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[realtimeUsage]}}", + "name": "realtimeUsage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.egressBytes" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Realtime Apps]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Realtime App]}}" + }, + "variables": [ + "{{variables.[Cloudflare Realtime App]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.egressBytes_sum", + "comparisonColumn": "none", + "label": "Bytes Sent" + } + } + } + } + }, + { + "i": "e337f997-f243-4bd0-bb7a-c744a75ee5bb", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[realtimeUsage]}}", + "name": "realtimeUsage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.ingressBytes" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Realtime Apps]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Realtime App]}}" + }, + "variables": [ + "{{variables.[Cloudflare Realtime App]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.ingressBytes_sum", + "comparisonColumn": "none", + "label": "Bytes Received" + } + } + } + } + }, + { + "i": "9989bf6a-9c82-4322-82a4-5de34f6e2d15", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[realtimeUsage]}}", + "name": "realtimeUsage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "distinctCount", + "names": [ + "dimensions.trackType" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Realtime Apps]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Realtime App]}}" + }, + "variables": [ + "{{variables.[Cloudflare Realtime App]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "dimensions.trackType_distinctCount", + "comparisonColumn": "none", + "label": "Track Types" + } + } + } + } + }, + { + "i": "173404ee-57ff-4d6e-a115-d6dbb62909a1", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[realtimeUsage]}}", + "name": "realtimeUsage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "max", + "names": [ + "sum.egressBytes" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Realtime Apps]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Realtime App]}}" + }, + "variables": [ + "{{variables.[Cloudflare Realtime App]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.egressBytes_max", + "comparisonColumn": "none", + "label": "Peak Daily Sent" + } + } + } + } + }, + { + "i": "436da462-ed14-4ed8-8e35-4397b5628ce7", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "App Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Realtime Apps]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Realtime App]}}" + }, + "variables": [ + "{{variables.[Cloudflare Realtime App]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "a06aa244-d7c9-4318-9736-8f90ec7e91cb", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Traffic Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[realtimeUsage]}}", + "name": "realtimeUsage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.egressBytes" + ] + }, + { + "type": "sum", + "names": [ + "sum.ingressBytes" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Realtime Apps]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Realtime App]}}" + }, + "variables": [ + "{{variables.[Cloudflare Realtime App]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "sum.egressBytes_sum", + "sum.ingressBytes_sum" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "17c9fb0f-268e-436c-a6c5-352f265bf3e0", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Bytes Sent by Track Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[realtimeUsage]}}", + "name": "realtimeUsage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.trackType", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.egressBytes" + ] + } + ] + }, + "sort": { + "by": [ + [ + "sum.egressBytes_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Realtime Apps]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Realtime App]}}" + }, + "variables": [ + "{{variables.[Cloudflare Realtime App]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "sum.egressBytes_sum", + "labelColumn": "dimensions.trackType_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "98a69785-4f4b-4f15-9aec-16bdbe6e6061", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Bytes Received by Track Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[realtimeUsage]}}", + "name": "realtimeUsage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.trackType", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.ingressBytes" + ] + } + ] + }, + "sort": { + "by": [ + [ + "sum.ingressBytes_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Realtime Apps]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Realtime App]}}" + }, + "variables": [ + "{{variables.[Cloudflare Realtime App]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "dimensions.trackType_uniqueValues", + "yAxisData": [ + "sum.ingressBytes_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/Media/streamVideo.dash.json b/plugins/Cloudflare/v1/defaultContent/Media/streamVideo.dash.json new file mode 100644 index 00000000..5862b162 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/Media/streamVideo.dash.json @@ -0,0 +1,668 @@ +{ + "name": "Stream Video", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": [ + "{{variables.[Cloudflare Stream Video]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "f577dc2e-deb3-4d64-b341-862bbf4e1f96", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[streamMinutesViewed]}}", + "name": "streamMinutesViewed", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.minutesViewed" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Stream Videos]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Stream Video]}}" + }, + "variables": [ + "{{variables.[Cloudflare Stream Video]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.minutesViewed_sum", + "comparisonColumn": "none", + "label": "Minutes Viewed" + } + } + } + } + }, + { + "i": "ee74e4f5-55c4-4304-8fe4-6e77b1f6a821", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[streamCmcd]}}", + "name": "streamCmcd", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "country" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sampleCount" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Stream Videos]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Stream Video]}}" + }, + "variables": [ + "{{variables.[Cloudflare Stream Video]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sampleCount_sum", + "comparisonColumn": "none", + "label": "Playback Samples" + } + } + } + } + }, + { + "i": "03038bcb-803b-43ab-8714-7e392a253705", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[streamCmcd]}}", + "name": "streamCmcd", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "country" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "mean", + "names": [ + "avgBufferingDurationMs" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Stream Videos]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Stream Video]}}" + }, + "variables": [ + "{{variables.[Cloudflare Stream Video]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "avgBufferingDurationMs_mean", + "comparisonColumn": "none", + "label": "Avg Buffering" + } + } + } + } + }, + { + "i": "67460204-3b8f-47d5-814c-efd43b15c299", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[streamCmcd]}}", + "name": "streamCmcd", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "country" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "mean", + "names": [ + "avgStartupBufferingDurationMs" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Stream Videos]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Stream Video]}}" + }, + "variables": [ + "{{variables.[Cloudflare Stream Video]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "avgStartupBufferingDurationMs_mean", + "comparisonColumn": "none", + "label": "Avg Startup Buffering" + } + } + } + } + }, + { + "i": "3767d07d-5760-4518-96b2-41216cabfc84", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Video Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Stream Videos]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Stream Video]}}" + }, + "variables": [ + "{{variables.[Cloudflare Stream Video]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "a091d752-74b8-4b00-b270-5368127b22e1", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Minutes Viewed", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[streamMinutesViewed]}}", + "name": "streamMinutesViewed", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.minutesViewed" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Stream Videos]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Stream Video]}}" + }, + "variables": [ + "{{variables.[Cloudflare Stream Video]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "sum.minutesViewed_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "e2c8a36e-61ef-4276-bf55-36cf8c20ddf6", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Buffering by Country", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[streamCmcd]}}", + "name": "streamCmcd", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "country" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "avgBufferingDurationMs" + ] + } + ] + }, + "sort": { + "by": [ + [ + "avgBufferingDurationMs_mean", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Stream Videos]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Stream Video]}}" + }, + "variables": [ + "{{variables.[Cloudflare Stream Video]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "avgBufferingDurationMs_mean" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "85ff9eb6-7d96-4adc-9143-a260fccd0b0f", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Playback Samples by Resolution", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[streamCmcd]}}", + "name": "streamCmcd", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "resolution" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sampleCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "sampleCount_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Stream Videos]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Stream Video]}}" + }, + "variables": [ + "{{variables.[Cloudflare Stream Video]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "sampleCount_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "93bba344-431c-4f6f-891d-f0cc35861386", + "x": 0, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Encoded Bitrate by Stream Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[streamCmcd]}}", + "name": "streamCmcd", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "streamType" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "avgEncodedBitrate" + ] + } + ] + }, + "sort": { + "by": [ + [ + "avgEncodedBitrate_mean", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Stream Videos]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Stream Video]}}" + }, + "variables": [ + "{{variables.[Cloudflare Stream Video]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "avgEncodedBitrate_mean" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "3e6c4bba-6800-4622-b3bd-b3b8e0dca3d6", + "x": 2, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Buffering Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[streamCmcd]}}", + "name": "streamCmcd", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "country" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "avgBufferingDurationMs" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Stream Videos]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Stream Video]}}" + }, + "variables": [ + "{{variables.[Cloudflare Stream Video]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "avgBufferingDurationMs_mean" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/d1Database.dash.json b/plugins/Cloudflare/v1/defaultContent/Storage & Databases/d1Database.dash.json similarity index 80% rename from plugins/Cloudflare/v1/defaultContent/d1Database.dash.json rename to plugins/Cloudflare/v1/defaultContent/Storage & Databases/d1Database.dash.json index 10c92d04..62f6be5d 100644 --- a/plugins/Cloudflare/v1/defaultContent/d1Database.dash.json +++ b/plugins/Cloudflare/v1/defaultContent/Storage & Databases/d1Database.dash.json @@ -577,6 +577,145 @@ } } } + }, + { + "i": "4a01e5eb-42a3-4a7d-afab-d2551abd0376", + "x": 0, + "y": 11, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Queries by Database Role", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[d1Queries]}}", + "name": "d1Queries", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.databaseRole", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare D1 Databases]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare D1 Database]}}" + }, + "variables": [ + "{{variables.[Cloudflare D1 Database]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count_sum", + "labelColumn": "dimensions.databaseRole_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "4f0a6709-af34-4c20-aede-c481af6c41d2", + "x": 2, + "y": 11, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Rows Returned", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[d1Queries]}}", + "name": "d1Queries", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetime", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.rowsReturned" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.datetime_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare D1 Databases]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare D1 Database]}}" + }, + "variables": [ + "{{variables.[Cloudflare D1 Database]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byDay", + "yAxisColumn": [ + "sum.rowsReturned_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } } ] } diff --git a/plugins/Cloudflare/v1/defaultContent/hyperdriveConfig.dash.json b/plugins/Cloudflare/v1/defaultContent/Storage & Databases/hyperdriveConfig.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/hyperdriveConfig.dash.json rename to plugins/Cloudflare/v1/defaultContent/Storage & Databases/hyperdriveConfig.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/kvNamespace.dash.json b/plugins/Cloudflare/v1/defaultContent/Storage & Databases/kvNamespace.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/kvNamespace.dash.json rename to plugins/Cloudflare/v1/defaultContent/Storage & Databases/kvNamespace.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Storage & Databases/manifest.json b/plugins/Cloudflare/v1/defaultContent/Storage & Databases/manifest.json new file mode 100644 index 00000000..009c56aa --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/Storage & Databases/manifest.json @@ -0,0 +1,20 @@ +{ + "items": [ + { + "name": "r2Bucket", + "type": "dashboard" + }, + { + "name": "d1Database", + "type": "dashboard" + }, + { + "name": "kvNamespace", + "type": "dashboard" + }, + { + "name": "hyperdriveConfig", + "type": "dashboard" + } + ] +} diff --git a/plugins/Cloudflare/v1/defaultContent/r2Bucket.dash.json b/plugins/Cloudflare/v1/defaultContent/Storage & Databases/r2Bucket.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/r2Bucket.dash.json rename to plugins/Cloudflare/v1/defaultContent/Storage & Databases/r2Bucket.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/loadBalancerPool.dash.json b/plugins/Cloudflare/v1/defaultContent/Traffic/loadBalancerPool.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/loadBalancerPool.dash.json rename to plugins/Cloudflare/v1/defaultContent/Traffic/loadBalancerPool.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Traffic/manifest.json b/plugins/Cloudflare/v1/defaultContent/Traffic/manifest.json new file mode 100644 index 00000000..de31d756 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/Traffic/manifest.json @@ -0,0 +1,8 @@ +{ + "items": [ + { + "name": "loadBalancerPool", + "type": "dashboard" + } + ] +} diff --git a/plugins/Cloudflare/v1/defaultContent/accessApplication.dash.json b/plugins/Cloudflare/v1/defaultContent/Zero Trust/accessApplication.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/accessApplication.dash.json rename to plugins/Cloudflare/v1/defaultContent/Zero Trust/accessApplication.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Zero Trust/manifest.json b/plugins/Cloudflare/v1/defaultContent/Zero Trust/manifest.json new file mode 100644 index 00000000..dc52a9b2 --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/Zero Trust/manifest.json @@ -0,0 +1,16 @@ +{ + "items": [ + { + "name": "tunnel", + "type": "dashboard" + }, + { + "name": "accessApplication", + "type": "dashboard" + }, + { + "name": "turnstileWidget", + "type": "dashboard" + } + ] +} diff --git a/plugins/Cloudflare/v1/defaultContent/tunnel.dash.json b/plugins/Cloudflare/v1/defaultContent/Zero Trust/tunnel.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/tunnel.dash.json rename to plugins/Cloudflare/v1/defaultContent/Zero Trust/tunnel.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Zero Trust/turnstileWidget.dash.json b/plugins/Cloudflare/v1/defaultContent/Zero Trust/turnstileWidget.dash.json new file mode 100644 index 00000000..468f9d3a --- /dev/null +++ b/plugins/Cloudflare/v1/defaultContent/Zero Trust/turnstileWidget.dash.json @@ -0,0 +1,514 @@ +{ + "name": "Turnstile Widget", + "schemaVersion": "1.5", + "timeframe": "last7days", + "variables": [ + "{{variables.[Cloudflare Turnstile Widget]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "bd31abaf-2d0c-43fd-a3b8-1d3bfbaf5fe8", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[turnstileChallenges]}}", + "name": "turnstileChallenges", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "eventType" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "challenges" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Turnstile Widgets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Turnstile Widget]}}" + }, + "variables": [ + "{{variables.[Cloudflare Turnstile Widget]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "challenges_sum", + "comparisonColumn": "none", + "label": "Challenges" + } + } + } + } + }, + { + "i": "932b5e77-d950-4100-9fc1-750549ebd313", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[turnstileChallenges]}}", + "name": "turnstileChallenges", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "eventType" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "max", + "names": [ + "challenges" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Turnstile Widgets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Turnstile Widget]}}" + }, + "variables": [ + "{{variables.[Cloudflare Turnstile Widget]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "challenges_max", + "comparisonColumn": "none", + "label": "Peak Challenges" + } + } + } + } + }, + { + "i": "cd91cfab-0e72-4b8b-a06e-6cec4aac31d4", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[turnstileChallenges]}}", + "name": "turnstileChallenges", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "eventType" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "distinctCount", + "names": [ + "breakdown" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Turnstile Widgets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Turnstile Widget]}}" + }, + "variables": [ + "{{variables.[Cloudflare Turnstile Widget]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "breakdown_distinctCount", + "comparisonColumn": "none", + "label": "Event Types" + } + } + } + } + }, + { + "i": "14d6304c-e8f9-4ff1-a02a-2b6443d6eca9", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[turnstileChallenges]}}", + "name": "turnstileChallenges", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "action" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "distinctCount", + "names": [ + "breakdown" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Turnstile Widgets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Turnstile Widget]}}" + }, + "variables": [ + "{{variables.[Cloudflare Turnstile Widget]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "breakdown_distinctCount", + "comparisonColumn": "none", + "label": "Actions" + } + } + } + } + }, + { + "i": "53563637-a7eb-4df5-a9fd-419f8ad7f261", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Widget Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Turnstile Widgets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Turnstile Widget]}}" + }, + "variables": [ + "{{variables.[Cloudflare Turnstile Widget]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "f5316d80-3f1e-45fb-bbb5-260b2dcb9b25", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Challenges Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[turnstileChallenges]}}", + "name": "turnstileChallenges", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "eventType" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "challenges" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Turnstile Widgets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Turnstile Widget]}}" + }, + "variables": [ + "{{variables.[Cloudflare Turnstile Widget]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "challenges_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "be0a2090-0dfd-4adb-b896-358712f1b091", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Challenges by Event Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[turnstileChallenges]}}", + "name": "turnstileChallenges", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "eventType" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "challenges" + ] + } + ] + }, + "sort": { + "by": [ + [ + "challenges_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Turnstile Widgets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Turnstile Widget]}}" + }, + "variables": [ + "{{variables.[Cloudflare Turnstile Widget]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "challenges_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "3c814883-df37-4482-be86-1d36caa933ad", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Top Challenge Actions", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[turnstileChallenges]}}", + "name": "turnstileChallenges", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "action" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "challenges" + ] + } + ] + }, + "sort": { + "by": [ + [ + "challenges_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Turnstile Widgets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Turnstile Widget]}}" + }, + "variables": [ + "{{variables.[Cloudflare Turnstile Widget]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "challenges_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v1/defaultContent/manifest.json b/plugins/Cloudflare/v1/defaultContent/manifest.json index f69a19ec..16109b00 100644 --- a/plugins/Cloudflare/v1/defaultContent/manifest.json +++ b/plugins/Cloudflare/v1/defaultContent/manifest.json @@ -5,68 +5,32 @@ "type": "dashboard" }, { - "name": "account", - "type": "dashboard" - }, - { - "name": "zone", - "type": "dashboard" - }, - { - "name": "worker", - "type": "dashboard" - }, - { - "name": "r2Bucket", - "type": "dashboard" - }, - { - "name": "pagesProject", - "type": "dashboard" - }, - { - "name": "d1Database", - "type": "dashboard" - }, - { - "name": "kvNamespace", - "type": "dashboard" + "name": "Core", + "type": "folder" }, { - "name": "queue", - "type": "dashboard" + "name": "Compute", + "type": "folder" }, { - "name": "tunnel", - "type": "dashboard" + "name": "Storage & Databases", + "type": "folder" }, { - "name": "loadBalancerPool", - "type": "dashboard" + "name": "AI", + "type": "folder" }, { - "name": "accessApplication", - "type": "dashboard" + "name": "Zero Trust", + "type": "folder" }, { - "name": "durableObjectNamespace", - "type": "dashboard" + "name": "Traffic", + "type": "folder" }, { - "name": "vectorizeIndex", - "type": "dashboard" - }, - { - "name": "hyperdriveConfig", - "type": "dashboard" - }, - { - "name": "workerRoute", - "type": "dashboard" - }, - { - "name": "workerBinding", - "type": "dashboard" + "name": "Media", + "type": "folder" } ] } diff --git a/plugins/Cloudflare/v1/defaultContent/overview.dash.json b/plugins/Cloudflare/v1/defaultContent/overview.dash.json index 73de2193..8b5577a1 100644 --- a/plugins/Cloudflare/v1/defaultContent/overview.dash.json +++ b/plugins/Cloudflare/v1/defaultContent/overview.dash.json @@ -1633,6 +1633,361 @@ } } } + }, + { + "i": "24cf5eb9-6bad-433f-a748-637d668a707b", + "x": 0, + "y": 44, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Stream Videos", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Stream Videos]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "statusState", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "c4afc6e8-d873-439e-b23a-524115490249", + "x": 2, + "y": 44, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Turnstile Widgets", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Turnstile Widgets]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "mode", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "f1c1ad4a-931b-4987-a772-d8367090ef02", + "x": 0, + "y": 47, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "AI Gateways", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare AI Gateways]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "ca16cfd0-c194-409b-94a6-4d4297c9254a", + "x": 2, + "y": 47, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "AutoRAGs", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare AutoRAGs]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "status", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "2dc4925f-e310-48f8-aa1a-8cc5b80e52d4", + "x": 0, + "y": 50, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Container Applications", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Container Applications]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "imageName", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "1ed1f8bb-409a-492e-a0fd-ca4a7682c558", + "x": 2, + "y": 50, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Pipelines", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Pipelines]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "endpoint", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "64731322-4823-4187-8d15-cfa52d8f0c58", + "x": 0, + "y": 53, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Realtime Apps", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Realtime Apps]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "linkColumn": "link", + "columns": 4, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } } ] } diff --git a/plugins/Cloudflare/v1/defaultContent/scopes.json b/plugins/Cloudflare/v1/defaultContent/scopes.json index ceefaab0..8dbbd7c3 100644 --- a/plugins/Cloudflare/v1/defaultContent/scopes.json +++ b/plugins/Cloudflare/v1/defaultContent/scopes.json @@ -270,5 +270,124 @@ "default": "none", "type": "object" } + }, + { + "name": "Cloudflare Stream Videos", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Stream Video" + ] + } + }, + "variable": { + "name": "Cloudflare Stream Video", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare Turnstile Widgets", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Turnstile Widget" + ] + } + }, + "variable": { + "name": "Cloudflare Turnstile Widget", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare AI Gateways", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare AI Gateway" + ] + } + }, + "variable": { + "name": "Cloudflare AI Gateway", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare AutoRAGs", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare AutoRAG" + ] + } + }, + "variable": { + "name": "Cloudflare AutoRAG", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare Container Applications", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Container Application" + ] + } + }, + "variable": { + "name": "Cloudflare Container Application", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare Pipelines", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Pipeline" + ] + } + }, + "variable": { + "name": "Cloudflare Pipeline", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } + }, + { + "name": "Cloudflare Realtime Apps", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Realtime App" + ] + } + }, + "variable": { + "name": "Cloudflare Realtime App", + "allowMultipleSelection": false, + "default": "none", + "type": "object" + } } ] diff --git a/plugins/Cloudflare/v1/defaultContent/workerBinding.dash.json b/plugins/Cloudflare/v1/defaultContent/workerBinding.dash.json deleted file mode 100644 index 4251bcfe..00000000 --- a/plugins/Cloudflare/v1/defaultContent/workerBinding.dash.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "name": "Worker Binding", - "schemaVersion": "1.5", - "timeframe": "none", - "variables": [ - "{{variables.[Cloudflare Worker Binding]}}" - ], - "dashboard": { - "_type": "layout/grid", - "columns": 4, - "version": 1, - "contents": [ - { - "i": "ea9ba9d6-1b0b-45dd-9ea9-c9d2f3d49cdd", - "x": 0, - "y": 0, - "w": 4, - "h": 4, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Binding Details", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties" - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Worker Bindings]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Worker Binding]}}" - }, - "variables": [ - "{{variables.[Cloudflare Worker Binding]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": true, - "hiddenColumns": [ - "id", - "label", - "link", - "links", - "sourceId", - "sourceName", - "type" - ] - } - } - } - } - } - ] - } -} diff --git a/plugins/Cloudflare/v1/defaultContent/workerRoute.dash.json b/plugins/Cloudflare/v1/defaultContent/workerRoute.dash.json deleted file mode 100644 index 681d388d..00000000 --- a/plugins/Cloudflare/v1/defaultContent/workerRoute.dash.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "name": "Worker Route", - "schemaVersion": "1.5", - "timeframe": "none", - "variables": [ - "{{variables.[Cloudflare Worker Route]}}" - ], - "dashboard": { - "_type": "layout/grid", - "columns": 4, - "version": 1, - "contents": [ - { - "i": "04b5665c-896e-4623-9dcf-cc298dc3c6cb", - "x": 0, - "y": 0, - "w": 4, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Route Details", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties" - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Worker Routes]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Worker Route]}}" - }, - "variables": [ - "{{variables.[Cloudflare Worker Route]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": true, - "hiddenColumns": [ - "id", - "label", - "link", - "links", - "sourceId", - "sourceName", - "type" - ] - } - } - } - } - } - ] - } -} diff --git a/plugins/Cloudflare/v1/docs/README.md b/plugins/Cloudflare/v1/docs/README.md index f59004a2..24ae2722 100644 --- a/plugins/Cloudflare/v1/docs/README.md +++ b/plugins/Cloudflare/v1/docs/README.md @@ -31,7 +31,7 @@ You will need a Cloudflare **API token**. Legacy Global API Keys are not support | **Zone** | SSL and Certificates | **Read** | | **Zone** | Health Checks | **Read** | - The Durable Objects, Vectorize and Hyperdrive endpoints were reachable in testing with the permissions above and needed nothing extra. If your account restricts those products and their imports come back empty, add their **Read** permissions too. The Zero Trust Gateway streams read through **Account Analytics**, so they need no separate Gateway permission. + The Durable Objects, Vectorize, Hyperdrive, Stream, Turnstile, AI Gateway, AutoRAG, Containers, Pipelines and Realtime endpoints were all reachable in testing with the permissions above and needed nothing extra. If your account restricts those products and their imports come back empty, add their **Read** permissions too. The Zero Trust Gateway streams read through **Account Analytics**, so they need no separate Gateway permission. 6. Under **Account Resources**, choose **Include → All accounts** (or select the specific accounts you want SquaredUp to see). 7. Under **Zone Resources**, choose **Include → All zones from an account** or **All zones**. @@ -57,9 +57,12 @@ On save, the plugin verifies the token against Cloudflare's token-verification e - **Web performance** - Core Web Vitals (Largest Contentful Paint, Interaction to Next Paint, Cumulative Layout Shift) and page-load volume from Cloudflare Web Analytics, per zone. - **Developer platform** - Worker invocations, errors, subrequests and CPU-time percentiles; R2 bucket operations and stored size; KV operations, latency and stored keys; D1 query counts, rows touched and database size; Queue message operations and backlog; Durable Object invocations and storage; Vectorize and Hyperdrive query volume; Workers AI inference by model; and Pages deployment history with branch and commit. - **Dependency mapping** - which Worker binds which KV namespace, R2 bucket, D1 database, queue, Durable Object namespace, Vectorize index or Hyperdrive config, and which zones each Worker serves. -- **Zero Trust** - Access application inventory and login attempts, Tunnel connector health, and Gateway DNS and HTTP filtering activity. +- **Zero Trust** - Access application inventory and login attempts, Tunnel connector health, Turnstile challenges, and Gateway DNS, HTTP and network filtering activity. +- **Media** - Cloudflare Stream minutes viewed and playback quality, Images request and transformation volume, and Realtime bandwidth. +- **AI platform** - AI Gateway requests, errors, cache and cost by model or provider; AutoRAG query volume; Vectorize; Workers AI inference; and Browser Rendering sessions. +- **Email** - Email Routing message flow and DMARC alignment per zone. -The out-of-the-box dashboards include a **Cloudflare Overview** plus a perspective for each indexed object type. +The out-of-the-box dashboards open with a **Cloudflare Overview**, with perspectives grouped by Cloudflare product family - Core, Compute, Storage & Databases, AI, Media, Zero Trust and Traffic. Worker Routes and Worker Bindings are indexed and drive the relationship graph but have no perspective of their own. ## Data streams @@ -84,19 +87,47 @@ The out-of-the-box dashboards include a **Cloudflare Overview** plus a perspecti - **Load Balancer Pool Health** - per-origin health, response code, response time and failure reason for a pool at each Cloudflare edge location. - **Access Logins** - daily Zero Trust login attempts for an Access application by identity provider, country and outcome. - **DNS Analytics** - authoritative DNS query volume and response time for a zone, grouped by query name, query type, response code or edge location. +- **Email Routing** - forwarded and rejected messages for a zone by action, status and rule. +- **DMARC Reports** - DMARC alignment for a zone by sending source, with pass rate and message volume. +- **Cache Reserve Operations** - read, write and delete operations against a zone's Cache Reserve. +- **Cache Reserve Storage** - bytes and object count held in a zone's Cache Reserve over time. +- **Health Check Events** - standalone health check results for a zone with status, region, failure reason and response time. +- **Network Error Logs** - browser-reported network errors for a zone by error type and edge location. +- **Page Shield Reports** - client-side scripts and resources observed on a zone. - **Web Analytics Page Loads** - page views and visits for a zone's hostnames, grouped by country, device type or referrer. - **Core Web Vitals** - P75 Largest Contentful Paint, Interaction to Next Paint and Cumulative Layout Shift for a zone's hostnames. - **Gateway DNS Queries** - Zero Trust Gateway DNS resolutions for an account by policy decision, category, location or query type. - **Gateway HTTP Requests** - Zero Trust Gateway proxied web requests for an account by action, host or category. +- **Gateway Network Sessions** - Zero Trust Gateway TCP and UDP sessions for an account by action, destination, protocol or device. - **Workers AI Inference** - Workers AI inference requests for an account by model, with token counts and average duration. - **Durable Object Invocations** - requests, errors and wall-time percentiles for a Durable Object namespace. - **Durable Object Storage** - stored bytes for a SQLite-backed Durable Object namespace over time. - **Vectorize Queries** - query volume and average latency for a Vectorize index. - **Vectorize Storage** - stored vector count and dimensions for a Vectorize index. - **Hyperdrive Queries** - query volume and average latency for a Hyperdrive configuration. +- **Gateway Network Sessions** - Zero Trust Gateway TCP and UDP sessions for an account by action, destination, protocol or device. +- **DNS Firewall Analytics** - DNS Firewall cluster query volume, response codes and processing time for an account. +- **Audit Logs** - account audit activity grouped by action, actor or resource type. +- **Images Requests** - Cloudflare Images request volume for an account. +- **Images Unique Transformations** - daily count of unique image transformations served for an account. +- **Pages Functions Invocations** - requests, errors and CPU time for the Pages Functions running in an account, by function. +- **Browser Rendering** - Browser Rendering session count and duration for an account. +- **Stream Minutes Viewed** - daily minutes viewed for a Cloudflare Stream video. +- **Stream Playback Quality** - playback buffering and bitrate for a Stream video, by country, resolution or stream type. +- **Realtime Usage** - ingress and egress bandwidth for a Realtime application by track type. +- **Turnstile Challenges** - challenges served by a Turnstile widget, by event type or action. +- **AI Gateway Requests** - requests, tokens, cost and duration through an AI Gateway, by model or provider. +- **AI Gateway Errors** - errored requests through an AI Gateway, by model or provider. +- **AI Gateway Cache** - cache hits and misses for an AI Gateway. +- **AutoRAG Queries** - AI Search query volume for an AutoRAG instance. +- **Container Metrics** - CPU, memory, uptime and network throughput for a container application. +- **Pipeline Ingestion** - records and bytes ingested by a pipeline. +- **Queue Consumer Metrics** - average consumer concurrency for a queue. +- **Durable Object Subrequests** - uncached subrequest body size for a Durable Object namespace. +- **D1 Query Insights** - query counts, rows touched and query duration percentiles for a D1 database. - **GraphQL Query** - runs any query you write against Cloudflare's GraphQL Analytics API, for the many datasets this plugin has no dedicated stream for. -Seventeen further streams back the import and the setup check and are hidden from the tile editor. +Twenty-four further streams back the import and the setup check and are hidden from the tile editor. ### Writing your own GraphQL queries @@ -127,6 +158,13 @@ Cloudflare's GraphQL Analytics API exposes far more datasets than this plugin sh | **Cloudflare Hyperdrive Config** | `GET /accounts/{id}/hyperdrive/configs` | A Hyperdrive database connection configuration. | | **Cloudflare Worker Route** | `GET /zones/{id}/workers/routes` | A URL pattern routing a zone's requests to a Worker. | | **Cloudflare Worker Binding** | `GET /accounts/{id}/workers/scripts/{name}/settings` | A resource bound to a Worker, such as a KV namespace or R2 bucket. | +| **Cloudflare Stream Video** | `GET /accounts/{id}/stream` | A video hosted on Cloudflare Stream. | +| **Cloudflare Turnstile Widget** | `GET /accounts/{id}/challenges/widgets` | A Turnstile challenge widget. | +| **Cloudflare AI Gateway** | `GET /accounts/{id}/ai-gateway/gateways` | An AI Gateway instance proxying model calls. | +| **Cloudflare AutoRAG** | `GET /accounts/{id}/autorag/rags` | An AutoRAG / AI Search instance. | +| **Cloudflare Container Application** | `GET /accounts/{id}/containers/applications` | A deployed container application. | +| **Cloudflare Pipeline** | `GET /accounts/{id}/pipelines` | A Cloudflare Pipelines data pipeline. | +| **Cloudflare Realtime App** | `GET /accounts/{id}/calls/apps` | A Cloudflare Realtime (Calls) application. | **Relationships:** the plugin ships correlation rules that draw edges between imported objects: @@ -146,17 +184,17 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w - **Analytics timeframes are capped per dataset, and the caps are short.** Cloudflare's GraphQL Analytics API limits how wide a single query's time range can be, and the limit differs for every dataset. These were measured against a Pro-plan account: - | Data stream | Widest single query | Timeframes offered | - | ----------- | ------------------- | ------------------ | - | **Zone Traffic** | 3 days | Last 12 hours, Last 24 hours | - | **Zone Firewall Events** | 1 day | Last 12 hours, Last 24 hours | - | **Load Balancing Requests** | ~3 days | Last 12 hours, Last 24 hours | - | **Zone Traffic Breakdown** | 8 days | Last 12 hours, Last 24 hours, Last 7 days | - | **Access Logins**, **DNS Analytics** | 1 week | up to Last 7 days | - | **Gateway DNS Queries**, **Gateway HTTP Requests** | ~30 days | up to Last 30 days | - | **KV**, **Workers AI**, **Durable Object**, **Vectorize**, **Hyperdrive** streams | ~32 days | up to Last 30 days | - | **Web Analytics Page Loads**, **Core Web Vitals** | ~93 days | up to Last 30 days | - | **Worker Invocations**, **R2**, **D1**, **Queue** streams | 30 days or more | up to Last 30 days | + | Widest single query | Data streams | + | ------------------- | ------------ | + | **1 day** | Zone Firewall Events | + | **~3 days** | Zone Traffic, Load Balancing Requests, Health Check Events | + | **~1 week** | DNS Analytics, Access Logins, Turnstile Challenges | + | **8 days** | Zone Traffic Breakdown | + | **~30-32 days** | the Gateway streams, KV, D1, R2, Queues, Workers AI, Durable Objects, Vectorize, Hyperdrive, Cache Reserve, Email Routing, DMARC, Images, AI Gateway, AutoRAG, Containers, Pipelines, Realtime, Browser Rendering, Stream | + | **~93 days** | Web Analytics Page Loads, Core Web Vitals | + | **~179 days** | Audit Logs | + + Every one of these was measured against the live API by widening the range until Cloudflare rejected it - none is documented. Caps may differ on other plans, and a few sit so close to a boundary that the next-widest option had to be dropped. Longer ranges are not offered because Cloudflare rejects them outright. Caps may differ on Free, Business and Enterprise plans. @@ -171,5 +209,9 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w - **Some resource lists are not paged.** R2 buckets, D1 databases, Queues, load balancer pools, Access applications, Vectorize indexes, Hyperdrive configs, Worker scripts and Worker routes are imported in a single request each. Where Cloudflare's paging behaviour could be proven against real data it is used (zones, accounts, DNS records, Pages projects, KV namespaces, Tunnels and Durable Object namespaces all page); the rest were left unpaged because the endpoint either ignores the paging parameters outright — as `workers/scripts` does — or holds too few records in the tested account to confirm they are honoured. If an account holds more of one of these than Cloudflare returns on a single page, the remainder is not imported. - **Rate limits.** The REST API allowed 1,200 requests per 300 seconds on the token tested, and Cloudflare documents a separate limit of 300 GraphQL queries per 5 minutes. Every analytics stream issues one request per selected object, so very large estates can hit these limits. - **Hand-written GraphQL queries are unbounded.** The **GraphQL Query** stream runs whatever you give it, so it can hit limits the built-in streams are tuned to avoid: a large `limit` on a multi-dimension dataset can exceed the ~6 MB response cap, and a timeframe wider than that dataset's own cap fails outright. Prefer the pre-aggregated `*Groups` datasets over raw event datasets, and keep `limit` modest. The stream does not page, so your `limit` is the ceiling. +- **Some analytics are only available on paid plans.** Page Shield and Network Error Logs return an authorization error on plans without them; Cache Reserve, Load Balancing and Health Checks are add-ons. An unentitled feature shows no data rather than an error in most tiles. +- **A failed Cloudflare query can look like "no data".** Cloudflare answers a failed GraphQL query with HTTP 200 and an `errors` array, which the platform does not treat as a failure. Streams that use a post-request script raise these errors explicitly, but the simpler declarative streams will show an empty tile instead of an error message. +- **Costs are unitless.** Cloudflare's AI Gateway analytics reports cost without stating a currency, so the plugin shows a plain number rather than assuming one. +- **Pages Functions cannot be scoped to a single project.** Cloudflare identifies Pages Functions by an internal script name with no published mapping to the project, so this stream reports all Pages Functions in the account, with the function name as a column. - **Imports run every 12 hours** by default, so newly created zones and resources are not visible immediately. - **Read-only.** The plugin never creates, modifies or deletes anything in Cloudflare. diff --git a/plugins/Cloudflare/v1/indexDefinitions/default.json b/plugins/Cloudflare/v1/indexDefinitions/default.json index 6a369d24..677775ab 100644 --- a/plugins/Cloudflare/v1/indexDefinitions/default.json +++ b/plugins/Cloudflare/v1/indexDefinitions/default.json @@ -461,6 +461,201 @@ "serviceName" ] } + }, + { + "name": "streamVideos", + "dataStream": { + "name": "streamVideos" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "videoName", + "type": { + "value": "Cloudflare Stream Video" + }, + "properties": [ + "accountId", + "statusState", + "duration", + "size", + "readyToStream", + "createdOn", + "preview" + ] + } + }, + { + "name": "turnstileWidgets", + "dataStream": { + "name": "turnstileWidgets" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "widgetName", + "type": { + "value": "Cloudflare Turnstile Widget" + }, + "properties": [ + "accountId", + "mode", + "region", + "domains", + "botFightMode", + "createdOn", + "modifiedOn" + ] + } + }, + { + "name": "aiGateways", + "dataStream": { + "name": "aiGateways" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "gatewayName", + "type": { + "value": "Cloudflare AI Gateway" + }, + "properties": [ + "accountId", + "cacheTtl", + "rateLimitingLimit", + "collectLogs", + "createdOn" + ] + } + }, + { + "name": "autoragInstances", + "dataStream": { + "name": "autoragInstances" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "ragName", + "type": { + "value": "Cloudflare AutoRAG" + }, + "properties": [ + "accountId", + "status", + "source", + "createdOn" + ] + } + }, + { + "name": "containerApps", + "dataStream": { + "name": "containerApps" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "appName", + "type": { + "value": "Cloudflare Container Application" + }, + "properties": [ + "accountId", + "instances", + "imageName", + "schedulingPolicy", + "createdOn" + ] + } + }, + { + "name": "pipelines", + "dataStream": { + "name": "pipelines" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "pipelineName", + "type": { + "value": "Cloudflare Pipeline" + }, + "properties": [ + "accountId", + "endpoint", + "createdOn" + ] + } + }, + { + "name": "realtimeApps", + "dataStream": { + "name": "realtimeApps" + }, + "scope": { + "query": "g.V().has(\"sourceType\", \"Cloudflare Account\")" + }, + "timeframe": "none", + "optional": true, + "dependsOn": [ + "accounts" + ], + "objectMapping": { + "id": "sourceId", + "name": "appName", + "type": { + "value": "Cloudflare Realtime App" + }, + "properties": [ + "accountId", + "createdOn", + "modifiedOn" + ] + } } ] } diff --git a/plugins/Cloudflare/v1/metadata.json b/plugins/Cloudflare/v1/metadata.json index 5ed67d31..322d1d6a 100644 --- a/plugins/Cloudflare/v1/metadata.json +++ b/plugins/Cloudflare/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "cloudflare", "displayName": "Cloudflare", - "version": "1.1.0", + "version": "1.4.0", "author": { "name": "@clarkd", "type": "community" @@ -34,7 +34,15 @@ "durable objects", "vectorize", "hyperdrive", - "ai" + "ai", + "stream", + "images", + "turnstile", + "autorag", + "containers", + "pipelines", + "realtime", + "media" ], "objectTypes": [ "Cloudflare Account", @@ -52,7 +60,14 @@ "Cloudflare Vectorize Index", "Cloudflare Hyperdrive Config", "Cloudflare Worker Route", - "Cloudflare Worker Binding" + "Cloudflare Worker Binding", + "Cloudflare Stream Video", + "Cloudflare Turnstile Widget", + "Cloudflare AI Gateway", + "Cloudflare AutoRAG", + "Cloudflare Container Application", + "Cloudflare Pipeline", + "Cloudflare Realtime App" ], "links": [ { From 8bdf7e008cd6d318989fc7032d0a6ae1d48e84f4 Mon Sep 17 00:00:00 2001 From: Dave Clarke Date: Tue, 18 Aug 2026 22:17:02 +0100 Subject: [PATCH 04/27] Reset Cloudflare to 1.0.0 for a new-plugin PR REVIEW.md on main now states that a new plugin stays at 1.0.0 for the life of its PR, since there is no version on main to compare against. Cloudflare does not exist on main, so the incremental bumps made while building it are not appropriate. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01CXgffao5bcMhNz3Ci7eCi9 --- plugins/Cloudflare/v1/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Cloudflare/v1/metadata.json b/plugins/Cloudflare/v1/metadata.json index 322d1d6a..5ce3dca8 100644 --- a/plugins/Cloudflare/v1/metadata.json +++ b/plugins/Cloudflare/v1/metadata.json @@ -1,7 +1,7 @@ { "name": "cloudflare", "displayName": "Cloudflare", - "version": "1.4.0", + "version": "1.0.0", "author": { "name": "@clarkd", "type": "community" From 34ecb076c972b40b99d13067d6607ba4ce87df40 Mon Sep 17 00:00:00 2001 From: Dave Clarke Date: Tue, 18 Aug 2026 22:24:14 +0100 Subject: [PATCH 05/27] Move Cloudflare to v2 and set version 2.0.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit REVIEW.md requires the major version to match the folder, so a 2.x.y plugin lives in v2/. Cloudflare's earlier version is a closed-source plugin maintained outside this repository, which is the same situation as plugins/UptimeRobot — the rules note a missing v1/ is not a mistake. Documentation links in metadata.json and ui.json updated to the v2 path. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01CXgffao5bcMhNz3Ci7eCi9 --- plugins/Cloudflare/{v1 => v2}/configValidation.json | 0 .../correlationRules/relate-pages-project-to-zone.json | 0 .../{v1 => v2}/correlationRules/relate-queue-to-worker.json | 0 .../correlationRules/relate-resources-to-account.json | 0 .../relate-worker-binding-to-d1-database.json | 0 .../relate-worker-binding-to-durable-object-namespace.json | 0 .../relate-worker-binding-to-hyperdrive-config.json | 0 .../relate-worker-binding-to-kv-namespace.json | 0 .../correlationRules/relate-worker-binding-to-queue.json | 0 .../correlationRules/relate-worker-binding-to-r2-bucket.json | 0 .../relate-worker-binding-to-vectorize-index.json | 0 .../correlationRules/relate-worker-binding-to-worker.json | 0 .../{v1 => v2}/correlationRules/relate-worker-to-zone.json | 0 plugins/Cloudflare/{v1 => v2}/custom_types.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/accessApps.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/accessLogins.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/accounts.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/aiGatewayCache.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/aiGatewayErrors.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/aiGatewayRequests.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/aiGateways.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/auditLogs.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/autoragInstances.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/autoragQueries.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/browserRendering.json | 0 .../{v1 => v2}/dataStreams/cacheReserveOperations.json | 0 .../{v1 => v2}/dataStreams/cacheReserveStorage.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/containerApps.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/containerMetrics.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/d1Analytics.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/d1Databases.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/d1Queries.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/d1Storage.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/dmarcReports.json | 0 .../{v1 => v2}/dataStreams/dnsFirewallAnalytics.json | 0 .../{v1 => v2}/dataStreams/durableObjectInvocations.json | 0 .../{v1 => v2}/dataStreams/durableObjectNamespaces.json | 0 .../{v1 => v2}/dataStreams/durableObjectStorage.json | 0 .../{v1 => v2}/dataStreams/durableObjectSubrequests.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/emailRouting.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/gatewayDnsQueries.json | 0 .../{v1 => v2}/dataStreams/gatewayHttpRequests.json | 0 .../{v1 => v2}/dataStreams/gatewayNetworkSessions.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/graphqlQuery.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/hyperdriveConfigs.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/hyperdriveQueries.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/imagesRequests.json | 0 .../{v1 => v2}/dataStreams/imagesTransformations.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/kvNamespaces.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/kvOperations.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/kvStorage.json | 0 .../{v1 => v2}/dataStreams/loadBalancerPoolHealth.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/loadBalancerPools.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/pagesDeployments.json | 0 .../{v1 => v2}/dataStreams/pagesFunctionsInvocations.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/pagesProjects.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/pipelineIngestion.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/pipelines.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/queueBacklog.json | 0 .../{v1 => v2}/dataStreams/queueConsumerMetrics.json | 0 .../{v1 => v2}/dataStreams/queueMessageOperations.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/queues.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/r2Buckets.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/r2Operations.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/r2Storage.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/realtimeApps.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/realtimeUsage.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/rumPageLoads.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/rumWebVitals.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/scripts/accessApps.js | 0 .../Cloudflare/{v1 => v2}/dataStreams/scripts/aiGateways.js | 0 .../Cloudflare/{v1 => v2}/dataStreams/scripts/auditLogs.js | 0 .../{v1 => v2}/dataStreams/scripts/autoragInstances.js | 0 .../{v1 => v2}/dataStreams/scripts/browserRendering.js | 0 .../{v1 => v2}/dataStreams/scripts/cacheReserveOperations.js | 0 .../{v1 => v2}/dataStreams/scripts/containerApps.js | 0 .../{v1 => v2}/dataStreams/scripts/containerMetrics.js | 0 .../Cloudflare/{v1 => v2}/dataStreams/scripts/d1Databases.js | 0 .../Cloudflare/{v1 => v2}/dataStreams/scripts/dmarcReports.js | 0 .../{v1 => v2}/dataStreams/scripts/dnsFirewallAnalytics.js | 0 .../{v1 => v2}/dataStreams/scripts/durableObjectNamespaces.js | 0 .../Cloudflare/{v1 => v2}/dataStreams/scripts/emailRouting.js | 0 .../{v1 => v2}/dataStreams/scripts/gatewayDnsQueries.js | 0 .../{v1 => v2}/dataStreams/scripts/gatewayHttpRequests.js | 0 .../{v1 => v2}/dataStreams/scripts/gatewayNetworkSessions.js | 0 .../Cloudflare/{v1 => v2}/dataStreams/scripts/graphqlQuery.js | 0 .../{v1 => v2}/dataStreams/scripts/hyperdriveConfigs.js | 0 .../{v1 => v2}/dataStreams/scripts/imagesRequests.js | 0 .../{v1 => v2}/dataStreams/scripts/imagesTransformations.js | 0 .../Cloudflare/{v1 => v2}/dataStreams/scripts/kvNamespaces.js | 0 .../{v1 => v2}/dataStreams/scripts/loadBalancerPoolHealth.js | 0 .../{v1 => v2}/dataStreams/scripts/loadBalancerPools.js | 0 .../{v1 => v2}/dataStreams/scripts/pagesDeployments.js | 0 .../{v1 => v2}/dataStreams/scripts/pagesProjects.js | 0 .../Cloudflare/{v1 => v2}/dataStreams/scripts/pipelines.js | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/queues.js | 0 .../Cloudflare/{v1 => v2}/dataStreams/scripts/r2Buckets.js | 0 .../Cloudflare/{v1 => v2}/dataStreams/scripts/realtimeApps.js | 0 .../Cloudflare/{v1 => v2}/dataStreams/scripts/rumPageLoads.js | 0 .../Cloudflare/{v1 => v2}/dataStreams/scripts/streamCmcd.js | 0 .../Cloudflare/{v1 => v2}/dataStreams/scripts/streamVideos.js | 0 .../{v1 => v2}/dataStreams/scripts/tunnelConnections.js | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/tunnels.js | 0 .../{v1 => v2}/dataStreams/scripts/turnstileChallenges.js | 0 .../{v1 => v2}/dataStreams/scripts/turnstileWidgets.js | 0 .../{v1 => v2}/dataStreams/scripts/vectorizeIndexes.js | 0 .../{v1 => v2}/dataStreams/scripts/workerBindings.js | 0 .../Cloudflare/{v1 => v2}/dataStreams/scripts/workerRoutes.js | 0 .../{v1 => v2}/dataStreams/scripts/workerScripts.js | 0 .../{v1 => v2}/dataStreams/scripts/workersAiInference.js | 0 .../{v1 => v2}/dataStreams/scripts/zoneCertificates.js | 0 .../{v1 => v2}/dataStreams/scripts/zoneDnsAnalytics.js | 0 .../{v1 => v2}/dataStreams/scripts/zoneFirewallEvents.js | 0 .../{v1 => v2}/dataStreams/scripts/zoneNelReports.js | 0 .../{v1 => v2}/dataStreams/scripts/zonePageShield.js | 0 .../{v1 => v2}/dataStreams/scripts/zoneTrafficBreakdown.js | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/streamCmcd.json | 0 .../{v1 => v2}/dataStreams/streamMinutesViewed.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/streamVideos.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/tunnelConnections.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/tunnels.json | 0 .../{v1 => v2}/dataStreams/turnstileChallenges.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/turnstileWidgets.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/vectorizeIndexes.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/vectorizeQueries.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/vectorizeStorage.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/verifyToken.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/workerBindings.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/workerInvocations.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/workerRoutes.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/workerScripts.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/workersAiInference.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/zoneCertificates.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/zoneDnsAnalytics.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/zoneDnsRecords.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/zoneFirewallEvents.json | 0 .../{v1 => v2}/dataStreams/zoneHealthCheckEvents.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/zoneHealthChecks.json | 0 .../Cloudflare/{v1 => v2}/dataStreams/zoneLoadBalancing.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/zoneNelReports.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/zonePageShield.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/zoneTraffic.json | 0 .../{v1 => v2}/dataStreams/zoneTrafficBreakdown.json | 0 plugins/Cloudflare/{v1 => v2}/dataStreams/zones.json | 0 .../{v1 => v2}/defaultContent/AI/aiGateway.dash.json | 0 .../Cloudflare/{v1 => v2}/defaultContent/AI/autorag.dash.json | 0 plugins/Cloudflare/{v1 => v2}/defaultContent/AI/manifest.json | 0 .../{v1 => v2}/defaultContent/AI/vectorizeIndex.dash.json | 0 .../defaultContent/Compute/containerApplication.dash.json | 0 .../defaultContent/Compute/durableObjectNamespace.dash.json | 0 .../{v1 => v2}/defaultContent/Compute/manifest.json | 0 .../{v1 => v2}/defaultContent/Compute/pagesProject.dash.json | 0 .../{v1 => v2}/defaultContent/Compute/pipeline.dash.json | 0 .../{v1 => v2}/defaultContent/Compute/queue.dash.json | 0 .../{v1 => v2}/defaultContent/Compute/worker.dash.json | 0 .../{v1 => v2}/defaultContent/Core/account.dash.json | 0 .../Cloudflare/{v1 => v2}/defaultContent/Core/manifest.json | 0 .../Cloudflare/{v1 => v2}/defaultContent/Core/zone.dash.json | 0 .../Cloudflare/{v1 => v2}/defaultContent/Media/manifest.json | 0 .../{v1 => v2}/defaultContent/Media/realtimeApp.dash.json | 0 .../{v1 => v2}/defaultContent/Media/streamVideo.dash.json | 0 .../defaultContent/Storage & Databases/d1Database.dash.json | 0 .../Storage & Databases/hyperdriveConfig.dash.json | 0 .../defaultContent/Storage & Databases/kvNamespace.dash.json | 0 .../defaultContent/Storage & Databases/manifest.json | 0 .../defaultContent/Storage & Databases/r2Bucket.dash.json | 0 .../defaultContent/Traffic/loadBalancerPool.dash.json | 0 .../{v1 => v2}/defaultContent/Traffic/manifest.json | 0 .../defaultContent/Zero Trust/accessApplication.dash.json | 0 .../{v1 => v2}/defaultContent/Zero Trust/manifest.json | 0 .../{v1 => v2}/defaultContent/Zero Trust/tunnel.dash.json | 0 .../defaultContent/Zero Trust/turnstileWidget.dash.json | 0 plugins/Cloudflare/{v1 => v2}/defaultContent/manifest.json | 0 .../Cloudflare/{v1 => v2}/defaultContent/overview.dash.json | 0 plugins/Cloudflare/{v1 => v2}/defaultContent/scopes.json | 0 plugins/Cloudflare/{v1 => v2}/docs/README.md | 0 plugins/Cloudflare/{v1 => v2}/icon.svg | 0 plugins/Cloudflare/{v1 => v2}/indexDefinitions/default.json | 0 plugins/Cloudflare/{v1 => v2}/metadata.json | 4 ++-- plugins/Cloudflare/{v1 => v2}/ui.json | 2 +- 180 files changed, 3 insertions(+), 3 deletions(-) rename plugins/Cloudflare/{v1 => v2}/configValidation.json (100%) rename plugins/Cloudflare/{v1 => v2}/correlationRules/relate-pages-project-to-zone.json (100%) rename plugins/Cloudflare/{v1 => v2}/correlationRules/relate-queue-to-worker.json (100%) rename plugins/Cloudflare/{v1 => v2}/correlationRules/relate-resources-to-account.json (100%) rename plugins/Cloudflare/{v1 => v2}/correlationRules/relate-worker-binding-to-d1-database.json (100%) rename plugins/Cloudflare/{v1 => v2}/correlationRules/relate-worker-binding-to-durable-object-namespace.json (100%) rename plugins/Cloudflare/{v1 => v2}/correlationRules/relate-worker-binding-to-hyperdrive-config.json (100%) rename plugins/Cloudflare/{v1 => v2}/correlationRules/relate-worker-binding-to-kv-namespace.json (100%) rename plugins/Cloudflare/{v1 => v2}/correlationRules/relate-worker-binding-to-queue.json (100%) rename plugins/Cloudflare/{v1 => v2}/correlationRules/relate-worker-binding-to-r2-bucket.json (100%) rename plugins/Cloudflare/{v1 => v2}/correlationRules/relate-worker-binding-to-vectorize-index.json (100%) rename plugins/Cloudflare/{v1 => v2}/correlationRules/relate-worker-binding-to-worker.json (100%) rename plugins/Cloudflare/{v1 => v2}/correlationRules/relate-worker-to-zone.json (100%) rename plugins/Cloudflare/{v1 => v2}/custom_types.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/accessApps.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/accessLogins.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/accounts.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/aiGatewayCache.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/aiGatewayErrors.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/aiGatewayRequests.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/aiGateways.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/auditLogs.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/autoragInstances.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/autoragQueries.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/browserRendering.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/cacheReserveOperations.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/cacheReserveStorage.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/containerApps.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/containerMetrics.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/d1Analytics.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/d1Databases.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/d1Queries.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/d1Storage.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/dmarcReports.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/dnsFirewallAnalytics.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/durableObjectInvocations.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/durableObjectNamespaces.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/durableObjectStorage.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/durableObjectSubrequests.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/emailRouting.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/gatewayDnsQueries.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/gatewayHttpRequests.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/gatewayNetworkSessions.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/graphqlQuery.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/hyperdriveConfigs.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/hyperdriveQueries.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/imagesRequests.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/imagesTransformations.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/kvNamespaces.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/kvOperations.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/kvStorage.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/loadBalancerPoolHealth.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/loadBalancerPools.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/pagesDeployments.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/pagesFunctionsInvocations.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/pagesProjects.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/pipelineIngestion.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/pipelines.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/queueBacklog.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/queueConsumerMetrics.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/queueMessageOperations.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/queues.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/r2Buckets.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/r2Operations.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/r2Storage.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/realtimeApps.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/realtimeUsage.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/rumPageLoads.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/rumWebVitals.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/accessApps.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/aiGateways.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/auditLogs.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/autoragInstances.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/browserRendering.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/cacheReserveOperations.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/containerApps.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/containerMetrics.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/d1Databases.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/dmarcReports.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/dnsFirewallAnalytics.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/durableObjectNamespaces.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/emailRouting.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/gatewayDnsQueries.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/gatewayHttpRequests.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/gatewayNetworkSessions.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/graphqlQuery.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/hyperdriveConfigs.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/imagesRequests.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/imagesTransformations.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/kvNamespaces.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/loadBalancerPoolHealth.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/loadBalancerPools.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/pagesDeployments.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/pagesProjects.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/pipelines.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/queues.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/r2Buckets.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/realtimeApps.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/rumPageLoads.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/streamCmcd.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/streamVideos.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/tunnelConnections.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/tunnels.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/turnstileChallenges.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/turnstileWidgets.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/vectorizeIndexes.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/workerBindings.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/workerRoutes.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/workerScripts.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/workersAiInference.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/zoneCertificates.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/zoneDnsAnalytics.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/zoneFirewallEvents.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/zoneNelReports.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/zonePageShield.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/scripts/zoneTrafficBreakdown.js (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/streamCmcd.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/streamMinutesViewed.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/streamVideos.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/tunnelConnections.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/tunnels.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/turnstileChallenges.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/turnstileWidgets.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/vectorizeIndexes.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/vectorizeQueries.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/vectorizeStorage.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/verifyToken.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/workerBindings.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/workerInvocations.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/workerRoutes.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/workerScripts.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/workersAiInference.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/zoneCertificates.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/zoneDnsAnalytics.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/zoneDnsRecords.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/zoneFirewallEvents.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/zoneHealthCheckEvents.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/zoneHealthChecks.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/zoneLoadBalancing.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/zoneNelReports.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/zonePageShield.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/zoneTraffic.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/zoneTrafficBreakdown.json (100%) rename plugins/Cloudflare/{v1 => v2}/dataStreams/zones.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/AI/aiGateway.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/AI/autorag.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/AI/manifest.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/AI/vectorizeIndex.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Compute/containerApplication.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Compute/durableObjectNamespace.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Compute/manifest.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Compute/pagesProject.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Compute/pipeline.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Compute/queue.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Compute/worker.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Core/account.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Core/manifest.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Core/zone.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Media/manifest.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Media/realtimeApp.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Media/streamVideo.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Storage & Databases/d1Database.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Storage & Databases/hyperdriveConfig.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Storage & Databases/kvNamespace.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Storage & Databases/manifest.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Storage & Databases/r2Bucket.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Traffic/loadBalancerPool.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Traffic/manifest.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Zero Trust/accessApplication.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Zero Trust/manifest.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Zero Trust/tunnel.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/Zero Trust/turnstileWidget.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/manifest.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/overview.dash.json (100%) rename plugins/Cloudflare/{v1 => v2}/defaultContent/scopes.json (100%) rename plugins/Cloudflare/{v1 => v2}/docs/README.md (100%) rename plugins/Cloudflare/{v1 => v2}/icon.svg (100%) rename plugins/Cloudflare/{v1 => v2}/indexDefinitions/default.json (100%) rename plugins/Cloudflare/{v1 => v2}/metadata.json (97%) rename plugins/Cloudflare/{v1 => v2}/ui.json (88%) diff --git a/plugins/Cloudflare/v1/configValidation.json b/plugins/Cloudflare/v2/configValidation.json similarity index 100% rename from plugins/Cloudflare/v1/configValidation.json rename to plugins/Cloudflare/v2/configValidation.json diff --git a/plugins/Cloudflare/v1/correlationRules/relate-pages-project-to-zone.json b/plugins/Cloudflare/v2/correlationRules/relate-pages-project-to-zone.json similarity index 100% rename from plugins/Cloudflare/v1/correlationRules/relate-pages-project-to-zone.json rename to plugins/Cloudflare/v2/correlationRules/relate-pages-project-to-zone.json diff --git a/plugins/Cloudflare/v1/correlationRules/relate-queue-to-worker.json b/plugins/Cloudflare/v2/correlationRules/relate-queue-to-worker.json similarity index 100% rename from plugins/Cloudflare/v1/correlationRules/relate-queue-to-worker.json rename to plugins/Cloudflare/v2/correlationRules/relate-queue-to-worker.json diff --git a/plugins/Cloudflare/v1/correlationRules/relate-resources-to-account.json b/plugins/Cloudflare/v2/correlationRules/relate-resources-to-account.json similarity index 100% rename from plugins/Cloudflare/v1/correlationRules/relate-resources-to-account.json rename to plugins/Cloudflare/v2/correlationRules/relate-resources-to-account.json diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-d1-database.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-d1-database.json similarity index 100% rename from plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-d1-database.json rename to plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-d1-database.json diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-durable-object-namespace.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-durable-object-namespace.json similarity index 100% rename from plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-durable-object-namespace.json rename to plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-durable-object-namespace.json diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-hyperdrive-config.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-hyperdrive-config.json similarity index 100% rename from plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-hyperdrive-config.json rename to plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-hyperdrive-config.json diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-kv-namespace.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-kv-namespace.json similarity index 100% rename from plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-kv-namespace.json rename to plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-kv-namespace.json diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-queue.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-queue.json similarity index 100% rename from plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-queue.json rename to plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-queue.json diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-r2-bucket.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-r2-bucket.json similarity index 100% rename from plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-r2-bucket.json rename to plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-r2-bucket.json diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-vectorize-index.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-vectorize-index.json similarity index 100% rename from plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-vectorize-index.json rename to plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-vectorize-index.json diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-worker.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-worker.json similarity index 100% rename from plugins/Cloudflare/v1/correlationRules/relate-worker-binding-to-worker.json rename to plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-worker.json diff --git a/plugins/Cloudflare/v1/correlationRules/relate-worker-to-zone.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-to-zone.json similarity index 100% rename from plugins/Cloudflare/v1/correlationRules/relate-worker-to-zone.json rename to plugins/Cloudflare/v2/correlationRules/relate-worker-to-zone.json diff --git a/plugins/Cloudflare/v1/custom_types.json b/plugins/Cloudflare/v2/custom_types.json similarity index 100% rename from plugins/Cloudflare/v1/custom_types.json rename to plugins/Cloudflare/v2/custom_types.json diff --git a/plugins/Cloudflare/v1/dataStreams/accessApps.json b/plugins/Cloudflare/v2/dataStreams/accessApps.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/accessApps.json rename to plugins/Cloudflare/v2/dataStreams/accessApps.json diff --git a/plugins/Cloudflare/v1/dataStreams/accessLogins.json b/plugins/Cloudflare/v2/dataStreams/accessLogins.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/accessLogins.json rename to plugins/Cloudflare/v2/dataStreams/accessLogins.json diff --git a/plugins/Cloudflare/v1/dataStreams/accounts.json b/plugins/Cloudflare/v2/dataStreams/accounts.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/accounts.json rename to plugins/Cloudflare/v2/dataStreams/accounts.json diff --git a/plugins/Cloudflare/v1/dataStreams/aiGatewayCache.json b/plugins/Cloudflare/v2/dataStreams/aiGatewayCache.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/aiGatewayCache.json rename to plugins/Cloudflare/v2/dataStreams/aiGatewayCache.json diff --git a/plugins/Cloudflare/v1/dataStreams/aiGatewayErrors.json b/plugins/Cloudflare/v2/dataStreams/aiGatewayErrors.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/aiGatewayErrors.json rename to plugins/Cloudflare/v2/dataStreams/aiGatewayErrors.json diff --git a/plugins/Cloudflare/v1/dataStreams/aiGatewayRequests.json b/plugins/Cloudflare/v2/dataStreams/aiGatewayRequests.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/aiGatewayRequests.json rename to plugins/Cloudflare/v2/dataStreams/aiGatewayRequests.json diff --git a/plugins/Cloudflare/v1/dataStreams/aiGateways.json b/plugins/Cloudflare/v2/dataStreams/aiGateways.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/aiGateways.json rename to plugins/Cloudflare/v2/dataStreams/aiGateways.json diff --git a/plugins/Cloudflare/v1/dataStreams/auditLogs.json b/plugins/Cloudflare/v2/dataStreams/auditLogs.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/auditLogs.json rename to plugins/Cloudflare/v2/dataStreams/auditLogs.json diff --git a/plugins/Cloudflare/v1/dataStreams/autoragInstances.json b/plugins/Cloudflare/v2/dataStreams/autoragInstances.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/autoragInstances.json rename to plugins/Cloudflare/v2/dataStreams/autoragInstances.json diff --git a/plugins/Cloudflare/v1/dataStreams/autoragQueries.json b/plugins/Cloudflare/v2/dataStreams/autoragQueries.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/autoragQueries.json rename to plugins/Cloudflare/v2/dataStreams/autoragQueries.json diff --git a/plugins/Cloudflare/v1/dataStreams/browserRendering.json b/plugins/Cloudflare/v2/dataStreams/browserRendering.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/browserRendering.json rename to plugins/Cloudflare/v2/dataStreams/browserRendering.json diff --git a/plugins/Cloudflare/v1/dataStreams/cacheReserveOperations.json b/plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/cacheReserveOperations.json rename to plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json diff --git a/plugins/Cloudflare/v1/dataStreams/cacheReserveStorage.json b/plugins/Cloudflare/v2/dataStreams/cacheReserveStorage.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/cacheReserveStorage.json rename to plugins/Cloudflare/v2/dataStreams/cacheReserveStorage.json diff --git a/plugins/Cloudflare/v1/dataStreams/containerApps.json b/plugins/Cloudflare/v2/dataStreams/containerApps.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/containerApps.json rename to plugins/Cloudflare/v2/dataStreams/containerApps.json diff --git a/plugins/Cloudflare/v1/dataStreams/containerMetrics.json b/plugins/Cloudflare/v2/dataStreams/containerMetrics.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/containerMetrics.json rename to plugins/Cloudflare/v2/dataStreams/containerMetrics.json diff --git a/plugins/Cloudflare/v1/dataStreams/d1Analytics.json b/plugins/Cloudflare/v2/dataStreams/d1Analytics.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/d1Analytics.json rename to plugins/Cloudflare/v2/dataStreams/d1Analytics.json diff --git a/plugins/Cloudflare/v1/dataStreams/d1Databases.json b/plugins/Cloudflare/v2/dataStreams/d1Databases.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/d1Databases.json rename to plugins/Cloudflare/v2/dataStreams/d1Databases.json diff --git a/plugins/Cloudflare/v1/dataStreams/d1Queries.json b/plugins/Cloudflare/v2/dataStreams/d1Queries.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/d1Queries.json rename to plugins/Cloudflare/v2/dataStreams/d1Queries.json diff --git a/plugins/Cloudflare/v1/dataStreams/d1Storage.json b/plugins/Cloudflare/v2/dataStreams/d1Storage.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/d1Storage.json rename to plugins/Cloudflare/v2/dataStreams/d1Storage.json diff --git a/plugins/Cloudflare/v1/dataStreams/dmarcReports.json b/plugins/Cloudflare/v2/dataStreams/dmarcReports.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/dmarcReports.json rename to plugins/Cloudflare/v2/dataStreams/dmarcReports.json diff --git a/plugins/Cloudflare/v1/dataStreams/dnsFirewallAnalytics.json b/plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/dnsFirewallAnalytics.json rename to plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json diff --git a/plugins/Cloudflare/v1/dataStreams/durableObjectInvocations.json b/plugins/Cloudflare/v2/dataStreams/durableObjectInvocations.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/durableObjectInvocations.json rename to plugins/Cloudflare/v2/dataStreams/durableObjectInvocations.json diff --git a/plugins/Cloudflare/v1/dataStreams/durableObjectNamespaces.json b/plugins/Cloudflare/v2/dataStreams/durableObjectNamespaces.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/durableObjectNamespaces.json rename to plugins/Cloudflare/v2/dataStreams/durableObjectNamespaces.json diff --git a/plugins/Cloudflare/v1/dataStreams/durableObjectStorage.json b/plugins/Cloudflare/v2/dataStreams/durableObjectStorage.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/durableObjectStorage.json rename to plugins/Cloudflare/v2/dataStreams/durableObjectStorage.json diff --git a/plugins/Cloudflare/v1/dataStreams/durableObjectSubrequests.json b/plugins/Cloudflare/v2/dataStreams/durableObjectSubrequests.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/durableObjectSubrequests.json rename to plugins/Cloudflare/v2/dataStreams/durableObjectSubrequests.json diff --git a/plugins/Cloudflare/v1/dataStreams/emailRouting.json b/plugins/Cloudflare/v2/dataStreams/emailRouting.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/emailRouting.json rename to plugins/Cloudflare/v2/dataStreams/emailRouting.json diff --git a/plugins/Cloudflare/v1/dataStreams/gatewayDnsQueries.json b/plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/gatewayDnsQueries.json rename to plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json diff --git a/plugins/Cloudflare/v1/dataStreams/gatewayHttpRequests.json b/plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/gatewayHttpRequests.json rename to plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json diff --git a/plugins/Cloudflare/v1/dataStreams/gatewayNetworkSessions.json b/plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/gatewayNetworkSessions.json rename to plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json diff --git a/plugins/Cloudflare/v1/dataStreams/graphqlQuery.json b/plugins/Cloudflare/v2/dataStreams/graphqlQuery.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/graphqlQuery.json rename to plugins/Cloudflare/v2/dataStreams/graphqlQuery.json diff --git a/plugins/Cloudflare/v1/dataStreams/hyperdriveConfigs.json b/plugins/Cloudflare/v2/dataStreams/hyperdriveConfigs.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/hyperdriveConfigs.json rename to plugins/Cloudflare/v2/dataStreams/hyperdriveConfigs.json diff --git a/plugins/Cloudflare/v1/dataStreams/hyperdriveQueries.json b/plugins/Cloudflare/v2/dataStreams/hyperdriveQueries.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/hyperdriveQueries.json rename to plugins/Cloudflare/v2/dataStreams/hyperdriveQueries.json diff --git a/plugins/Cloudflare/v1/dataStreams/imagesRequests.json b/plugins/Cloudflare/v2/dataStreams/imagesRequests.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/imagesRequests.json rename to plugins/Cloudflare/v2/dataStreams/imagesRequests.json diff --git a/plugins/Cloudflare/v1/dataStreams/imagesTransformations.json b/plugins/Cloudflare/v2/dataStreams/imagesTransformations.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/imagesTransformations.json rename to plugins/Cloudflare/v2/dataStreams/imagesTransformations.json diff --git a/plugins/Cloudflare/v1/dataStreams/kvNamespaces.json b/plugins/Cloudflare/v2/dataStreams/kvNamespaces.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/kvNamespaces.json rename to plugins/Cloudflare/v2/dataStreams/kvNamespaces.json diff --git a/plugins/Cloudflare/v1/dataStreams/kvOperations.json b/plugins/Cloudflare/v2/dataStreams/kvOperations.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/kvOperations.json rename to plugins/Cloudflare/v2/dataStreams/kvOperations.json diff --git a/plugins/Cloudflare/v1/dataStreams/kvStorage.json b/plugins/Cloudflare/v2/dataStreams/kvStorage.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/kvStorage.json rename to plugins/Cloudflare/v2/dataStreams/kvStorage.json diff --git a/plugins/Cloudflare/v1/dataStreams/loadBalancerPoolHealth.json b/plugins/Cloudflare/v2/dataStreams/loadBalancerPoolHealth.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/loadBalancerPoolHealth.json rename to plugins/Cloudflare/v2/dataStreams/loadBalancerPoolHealth.json diff --git a/plugins/Cloudflare/v1/dataStreams/loadBalancerPools.json b/plugins/Cloudflare/v2/dataStreams/loadBalancerPools.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/loadBalancerPools.json rename to plugins/Cloudflare/v2/dataStreams/loadBalancerPools.json diff --git a/plugins/Cloudflare/v1/dataStreams/pagesDeployments.json b/plugins/Cloudflare/v2/dataStreams/pagesDeployments.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/pagesDeployments.json rename to plugins/Cloudflare/v2/dataStreams/pagesDeployments.json diff --git a/plugins/Cloudflare/v1/dataStreams/pagesFunctionsInvocations.json b/plugins/Cloudflare/v2/dataStreams/pagesFunctionsInvocations.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/pagesFunctionsInvocations.json rename to plugins/Cloudflare/v2/dataStreams/pagesFunctionsInvocations.json diff --git a/plugins/Cloudflare/v1/dataStreams/pagesProjects.json b/plugins/Cloudflare/v2/dataStreams/pagesProjects.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/pagesProjects.json rename to plugins/Cloudflare/v2/dataStreams/pagesProjects.json diff --git a/plugins/Cloudflare/v1/dataStreams/pipelineIngestion.json b/plugins/Cloudflare/v2/dataStreams/pipelineIngestion.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/pipelineIngestion.json rename to plugins/Cloudflare/v2/dataStreams/pipelineIngestion.json diff --git a/plugins/Cloudflare/v1/dataStreams/pipelines.json b/plugins/Cloudflare/v2/dataStreams/pipelines.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/pipelines.json rename to plugins/Cloudflare/v2/dataStreams/pipelines.json diff --git a/plugins/Cloudflare/v1/dataStreams/queueBacklog.json b/plugins/Cloudflare/v2/dataStreams/queueBacklog.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/queueBacklog.json rename to plugins/Cloudflare/v2/dataStreams/queueBacklog.json diff --git a/plugins/Cloudflare/v1/dataStreams/queueConsumerMetrics.json b/plugins/Cloudflare/v2/dataStreams/queueConsumerMetrics.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/queueConsumerMetrics.json rename to plugins/Cloudflare/v2/dataStreams/queueConsumerMetrics.json diff --git a/plugins/Cloudflare/v1/dataStreams/queueMessageOperations.json b/plugins/Cloudflare/v2/dataStreams/queueMessageOperations.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/queueMessageOperations.json rename to plugins/Cloudflare/v2/dataStreams/queueMessageOperations.json diff --git a/plugins/Cloudflare/v1/dataStreams/queues.json b/plugins/Cloudflare/v2/dataStreams/queues.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/queues.json rename to plugins/Cloudflare/v2/dataStreams/queues.json diff --git a/plugins/Cloudflare/v1/dataStreams/r2Buckets.json b/plugins/Cloudflare/v2/dataStreams/r2Buckets.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/r2Buckets.json rename to plugins/Cloudflare/v2/dataStreams/r2Buckets.json diff --git a/plugins/Cloudflare/v1/dataStreams/r2Operations.json b/plugins/Cloudflare/v2/dataStreams/r2Operations.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/r2Operations.json rename to plugins/Cloudflare/v2/dataStreams/r2Operations.json diff --git a/plugins/Cloudflare/v1/dataStreams/r2Storage.json b/plugins/Cloudflare/v2/dataStreams/r2Storage.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/r2Storage.json rename to plugins/Cloudflare/v2/dataStreams/r2Storage.json diff --git a/plugins/Cloudflare/v1/dataStreams/realtimeApps.json b/plugins/Cloudflare/v2/dataStreams/realtimeApps.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/realtimeApps.json rename to plugins/Cloudflare/v2/dataStreams/realtimeApps.json diff --git a/plugins/Cloudflare/v1/dataStreams/realtimeUsage.json b/plugins/Cloudflare/v2/dataStreams/realtimeUsage.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/realtimeUsage.json rename to plugins/Cloudflare/v2/dataStreams/realtimeUsage.json diff --git a/plugins/Cloudflare/v1/dataStreams/rumPageLoads.json b/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/rumPageLoads.json rename to plugins/Cloudflare/v2/dataStreams/rumPageLoads.json diff --git a/plugins/Cloudflare/v1/dataStreams/rumWebVitals.json b/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/rumWebVitals.json rename to plugins/Cloudflare/v2/dataStreams/rumWebVitals.json diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/accessApps.js b/plugins/Cloudflare/v2/dataStreams/scripts/accessApps.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/accessApps.js rename to plugins/Cloudflare/v2/dataStreams/scripts/accessApps.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/aiGateways.js b/plugins/Cloudflare/v2/dataStreams/scripts/aiGateways.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/aiGateways.js rename to plugins/Cloudflare/v2/dataStreams/scripts/aiGateways.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/auditLogs.js b/plugins/Cloudflare/v2/dataStreams/scripts/auditLogs.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/auditLogs.js rename to plugins/Cloudflare/v2/dataStreams/scripts/auditLogs.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/autoragInstances.js b/plugins/Cloudflare/v2/dataStreams/scripts/autoragInstances.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/autoragInstances.js rename to plugins/Cloudflare/v2/dataStreams/scripts/autoragInstances.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/browserRendering.js b/plugins/Cloudflare/v2/dataStreams/scripts/browserRendering.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/browserRendering.js rename to plugins/Cloudflare/v2/dataStreams/scripts/browserRendering.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/cacheReserveOperations.js b/plugins/Cloudflare/v2/dataStreams/scripts/cacheReserveOperations.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/cacheReserveOperations.js rename to plugins/Cloudflare/v2/dataStreams/scripts/cacheReserveOperations.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/containerApps.js b/plugins/Cloudflare/v2/dataStreams/scripts/containerApps.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/containerApps.js rename to plugins/Cloudflare/v2/dataStreams/scripts/containerApps.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/containerMetrics.js b/plugins/Cloudflare/v2/dataStreams/scripts/containerMetrics.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/containerMetrics.js rename to plugins/Cloudflare/v2/dataStreams/scripts/containerMetrics.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/d1Databases.js b/plugins/Cloudflare/v2/dataStreams/scripts/d1Databases.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/d1Databases.js rename to plugins/Cloudflare/v2/dataStreams/scripts/d1Databases.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/dmarcReports.js b/plugins/Cloudflare/v2/dataStreams/scripts/dmarcReports.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/dmarcReports.js rename to plugins/Cloudflare/v2/dataStreams/scripts/dmarcReports.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/dnsFirewallAnalytics.js b/plugins/Cloudflare/v2/dataStreams/scripts/dnsFirewallAnalytics.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/dnsFirewallAnalytics.js rename to plugins/Cloudflare/v2/dataStreams/scripts/dnsFirewallAnalytics.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/durableObjectNamespaces.js b/plugins/Cloudflare/v2/dataStreams/scripts/durableObjectNamespaces.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/durableObjectNamespaces.js rename to plugins/Cloudflare/v2/dataStreams/scripts/durableObjectNamespaces.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/emailRouting.js b/plugins/Cloudflare/v2/dataStreams/scripts/emailRouting.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/emailRouting.js rename to plugins/Cloudflare/v2/dataStreams/scripts/emailRouting.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/gatewayDnsQueries.js b/plugins/Cloudflare/v2/dataStreams/scripts/gatewayDnsQueries.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/gatewayDnsQueries.js rename to plugins/Cloudflare/v2/dataStreams/scripts/gatewayDnsQueries.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/gatewayHttpRequests.js b/plugins/Cloudflare/v2/dataStreams/scripts/gatewayHttpRequests.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/gatewayHttpRequests.js rename to plugins/Cloudflare/v2/dataStreams/scripts/gatewayHttpRequests.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/gatewayNetworkSessions.js b/plugins/Cloudflare/v2/dataStreams/scripts/gatewayNetworkSessions.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/gatewayNetworkSessions.js rename to plugins/Cloudflare/v2/dataStreams/scripts/gatewayNetworkSessions.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/graphqlQuery.js b/plugins/Cloudflare/v2/dataStreams/scripts/graphqlQuery.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/graphqlQuery.js rename to plugins/Cloudflare/v2/dataStreams/scripts/graphqlQuery.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/hyperdriveConfigs.js b/plugins/Cloudflare/v2/dataStreams/scripts/hyperdriveConfigs.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/hyperdriveConfigs.js rename to plugins/Cloudflare/v2/dataStreams/scripts/hyperdriveConfigs.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/imagesRequests.js b/plugins/Cloudflare/v2/dataStreams/scripts/imagesRequests.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/imagesRequests.js rename to plugins/Cloudflare/v2/dataStreams/scripts/imagesRequests.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/imagesTransformations.js b/plugins/Cloudflare/v2/dataStreams/scripts/imagesTransformations.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/imagesTransformations.js rename to plugins/Cloudflare/v2/dataStreams/scripts/imagesTransformations.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/kvNamespaces.js b/plugins/Cloudflare/v2/dataStreams/scripts/kvNamespaces.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/kvNamespaces.js rename to plugins/Cloudflare/v2/dataStreams/scripts/kvNamespaces.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/loadBalancerPoolHealth.js b/plugins/Cloudflare/v2/dataStreams/scripts/loadBalancerPoolHealth.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/loadBalancerPoolHealth.js rename to plugins/Cloudflare/v2/dataStreams/scripts/loadBalancerPoolHealth.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/loadBalancerPools.js b/plugins/Cloudflare/v2/dataStreams/scripts/loadBalancerPools.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/loadBalancerPools.js rename to plugins/Cloudflare/v2/dataStreams/scripts/loadBalancerPools.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/pagesDeployments.js b/plugins/Cloudflare/v2/dataStreams/scripts/pagesDeployments.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/pagesDeployments.js rename to plugins/Cloudflare/v2/dataStreams/scripts/pagesDeployments.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/pagesProjects.js b/plugins/Cloudflare/v2/dataStreams/scripts/pagesProjects.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/pagesProjects.js rename to plugins/Cloudflare/v2/dataStreams/scripts/pagesProjects.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/pipelines.js b/plugins/Cloudflare/v2/dataStreams/scripts/pipelines.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/pipelines.js rename to plugins/Cloudflare/v2/dataStreams/scripts/pipelines.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/queues.js b/plugins/Cloudflare/v2/dataStreams/scripts/queues.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/queues.js rename to plugins/Cloudflare/v2/dataStreams/scripts/queues.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/r2Buckets.js b/plugins/Cloudflare/v2/dataStreams/scripts/r2Buckets.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/r2Buckets.js rename to plugins/Cloudflare/v2/dataStreams/scripts/r2Buckets.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/realtimeApps.js b/plugins/Cloudflare/v2/dataStreams/scripts/realtimeApps.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/realtimeApps.js rename to plugins/Cloudflare/v2/dataStreams/scripts/realtimeApps.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/rumPageLoads.js b/plugins/Cloudflare/v2/dataStreams/scripts/rumPageLoads.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/rumPageLoads.js rename to plugins/Cloudflare/v2/dataStreams/scripts/rumPageLoads.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/streamCmcd.js b/plugins/Cloudflare/v2/dataStreams/scripts/streamCmcd.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/streamCmcd.js rename to plugins/Cloudflare/v2/dataStreams/scripts/streamCmcd.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/streamVideos.js b/plugins/Cloudflare/v2/dataStreams/scripts/streamVideos.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/streamVideos.js rename to plugins/Cloudflare/v2/dataStreams/scripts/streamVideos.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/tunnelConnections.js b/plugins/Cloudflare/v2/dataStreams/scripts/tunnelConnections.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/tunnelConnections.js rename to plugins/Cloudflare/v2/dataStreams/scripts/tunnelConnections.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/tunnels.js b/plugins/Cloudflare/v2/dataStreams/scripts/tunnels.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/tunnels.js rename to plugins/Cloudflare/v2/dataStreams/scripts/tunnels.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/turnstileChallenges.js b/plugins/Cloudflare/v2/dataStreams/scripts/turnstileChallenges.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/turnstileChallenges.js rename to plugins/Cloudflare/v2/dataStreams/scripts/turnstileChallenges.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/turnstileWidgets.js b/plugins/Cloudflare/v2/dataStreams/scripts/turnstileWidgets.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/turnstileWidgets.js rename to plugins/Cloudflare/v2/dataStreams/scripts/turnstileWidgets.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/vectorizeIndexes.js b/plugins/Cloudflare/v2/dataStreams/scripts/vectorizeIndexes.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/vectorizeIndexes.js rename to plugins/Cloudflare/v2/dataStreams/scripts/vectorizeIndexes.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/workerBindings.js b/plugins/Cloudflare/v2/dataStreams/scripts/workerBindings.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/workerBindings.js rename to plugins/Cloudflare/v2/dataStreams/scripts/workerBindings.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/workerRoutes.js b/plugins/Cloudflare/v2/dataStreams/scripts/workerRoutes.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/workerRoutes.js rename to plugins/Cloudflare/v2/dataStreams/scripts/workerRoutes.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/workerScripts.js b/plugins/Cloudflare/v2/dataStreams/scripts/workerScripts.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/workerScripts.js rename to plugins/Cloudflare/v2/dataStreams/scripts/workerScripts.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/workersAiInference.js b/plugins/Cloudflare/v2/dataStreams/scripts/workersAiInference.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/workersAiInference.js rename to plugins/Cloudflare/v2/dataStreams/scripts/workersAiInference.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/zoneCertificates.js b/plugins/Cloudflare/v2/dataStreams/scripts/zoneCertificates.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/zoneCertificates.js rename to plugins/Cloudflare/v2/dataStreams/scripts/zoneCertificates.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/zoneDnsAnalytics.js b/plugins/Cloudflare/v2/dataStreams/scripts/zoneDnsAnalytics.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/zoneDnsAnalytics.js rename to plugins/Cloudflare/v2/dataStreams/scripts/zoneDnsAnalytics.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/zoneFirewallEvents.js b/plugins/Cloudflare/v2/dataStreams/scripts/zoneFirewallEvents.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/zoneFirewallEvents.js rename to plugins/Cloudflare/v2/dataStreams/scripts/zoneFirewallEvents.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/zoneNelReports.js b/plugins/Cloudflare/v2/dataStreams/scripts/zoneNelReports.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/zoneNelReports.js rename to plugins/Cloudflare/v2/dataStreams/scripts/zoneNelReports.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/zonePageShield.js b/plugins/Cloudflare/v2/dataStreams/scripts/zonePageShield.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/zonePageShield.js rename to plugins/Cloudflare/v2/dataStreams/scripts/zonePageShield.js diff --git a/plugins/Cloudflare/v1/dataStreams/scripts/zoneTrafficBreakdown.js b/plugins/Cloudflare/v2/dataStreams/scripts/zoneTrafficBreakdown.js similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/scripts/zoneTrafficBreakdown.js rename to plugins/Cloudflare/v2/dataStreams/scripts/zoneTrafficBreakdown.js diff --git a/plugins/Cloudflare/v1/dataStreams/streamCmcd.json b/plugins/Cloudflare/v2/dataStreams/streamCmcd.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/streamCmcd.json rename to plugins/Cloudflare/v2/dataStreams/streamCmcd.json diff --git a/plugins/Cloudflare/v1/dataStreams/streamMinutesViewed.json b/plugins/Cloudflare/v2/dataStreams/streamMinutesViewed.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/streamMinutesViewed.json rename to plugins/Cloudflare/v2/dataStreams/streamMinutesViewed.json diff --git a/plugins/Cloudflare/v1/dataStreams/streamVideos.json b/plugins/Cloudflare/v2/dataStreams/streamVideos.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/streamVideos.json rename to plugins/Cloudflare/v2/dataStreams/streamVideos.json diff --git a/plugins/Cloudflare/v1/dataStreams/tunnelConnections.json b/plugins/Cloudflare/v2/dataStreams/tunnelConnections.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/tunnelConnections.json rename to plugins/Cloudflare/v2/dataStreams/tunnelConnections.json diff --git a/plugins/Cloudflare/v1/dataStreams/tunnels.json b/plugins/Cloudflare/v2/dataStreams/tunnels.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/tunnels.json rename to plugins/Cloudflare/v2/dataStreams/tunnels.json diff --git a/plugins/Cloudflare/v1/dataStreams/turnstileChallenges.json b/plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/turnstileChallenges.json rename to plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json diff --git a/plugins/Cloudflare/v1/dataStreams/turnstileWidgets.json b/plugins/Cloudflare/v2/dataStreams/turnstileWidgets.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/turnstileWidgets.json rename to plugins/Cloudflare/v2/dataStreams/turnstileWidgets.json diff --git a/plugins/Cloudflare/v1/dataStreams/vectorizeIndexes.json b/plugins/Cloudflare/v2/dataStreams/vectorizeIndexes.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/vectorizeIndexes.json rename to plugins/Cloudflare/v2/dataStreams/vectorizeIndexes.json diff --git a/plugins/Cloudflare/v1/dataStreams/vectorizeQueries.json b/plugins/Cloudflare/v2/dataStreams/vectorizeQueries.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/vectorizeQueries.json rename to plugins/Cloudflare/v2/dataStreams/vectorizeQueries.json diff --git a/plugins/Cloudflare/v1/dataStreams/vectorizeStorage.json b/plugins/Cloudflare/v2/dataStreams/vectorizeStorage.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/vectorizeStorage.json rename to plugins/Cloudflare/v2/dataStreams/vectorizeStorage.json diff --git a/plugins/Cloudflare/v1/dataStreams/verifyToken.json b/plugins/Cloudflare/v2/dataStreams/verifyToken.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/verifyToken.json rename to plugins/Cloudflare/v2/dataStreams/verifyToken.json diff --git a/plugins/Cloudflare/v1/dataStreams/workerBindings.json b/plugins/Cloudflare/v2/dataStreams/workerBindings.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/workerBindings.json rename to plugins/Cloudflare/v2/dataStreams/workerBindings.json diff --git a/plugins/Cloudflare/v1/dataStreams/workerInvocations.json b/plugins/Cloudflare/v2/dataStreams/workerInvocations.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/workerInvocations.json rename to plugins/Cloudflare/v2/dataStreams/workerInvocations.json diff --git a/plugins/Cloudflare/v1/dataStreams/workerRoutes.json b/plugins/Cloudflare/v2/dataStreams/workerRoutes.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/workerRoutes.json rename to plugins/Cloudflare/v2/dataStreams/workerRoutes.json diff --git a/plugins/Cloudflare/v1/dataStreams/workerScripts.json b/plugins/Cloudflare/v2/dataStreams/workerScripts.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/workerScripts.json rename to plugins/Cloudflare/v2/dataStreams/workerScripts.json diff --git a/plugins/Cloudflare/v1/dataStreams/workersAiInference.json b/plugins/Cloudflare/v2/dataStreams/workersAiInference.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/workersAiInference.json rename to plugins/Cloudflare/v2/dataStreams/workersAiInference.json diff --git a/plugins/Cloudflare/v1/dataStreams/zoneCertificates.json b/plugins/Cloudflare/v2/dataStreams/zoneCertificates.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/zoneCertificates.json rename to plugins/Cloudflare/v2/dataStreams/zoneCertificates.json diff --git a/plugins/Cloudflare/v1/dataStreams/zoneDnsAnalytics.json b/plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/zoneDnsAnalytics.json rename to plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json diff --git a/plugins/Cloudflare/v1/dataStreams/zoneDnsRecords.json b/plugins/Cloudflare/v2/dataStreams/zoneDnsRecords.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/zoneDnsRecords.json rename to plugins/Cloudflare/v2/dataStreams/zoneDnsRecords.json diff --git a/plugins/Cloudflare/v1/dataStreams/zoneFirewallEvents.json b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/zoneFirewallEvents.json rename to plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json diff --git a/plugins/Cloudflare/v1/dataStreams/zoneHealthCheckEvents.json b/plugins/Cloudflare/v2/dataStreams/zoneHealthCheckEvents.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/zoneHealthCheckEvents.json rename to plugins/Cloudflare/v2/dataStreams/zoneHealthCheckEvents.json diff --git a/plugins/Cloudflare/v1/dataStreams/zoneHealthChecks.json b/plugins/Cloudflare/v2/dataStreams/zoneHealthChecks.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/zoneHealthChecks.json rename to plugins/Cloudflare/v2/dataStreams/zoneHealthChecks.json diff --git a/plugins/Cloudflare/v1/dataStreams/zoneLoadBalancing.json b/plugins/Cloudflare/v2/dataStreams/zoneLoadBalancing.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/zoneLoadBalancing.json rename to plugins/Cloudflare/v2/dataStreams/zoneLoadBalancing.json diff --git a/plugins/Cloudflare/v1/dataStreams/zoneNelReports.json b/plugins/Cloudflare/v2/dataStreams/zoneNelReports.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/zoneNelReports.json rename to plugins/Cloudflare/v2/dataStreams/zoneNelReports.json diff --git a/plugins/Cloudflare/v1/dataStreams/zonePageShield.json b/plugins/Cloudflare/v2/dataStreams/zonePageShield.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/zonePageShield.json rename to plugins/Cloudflare/v2/dataStreams/zonePageShield.json diff --git a/plugins/Cloudflare/v1/dataStreams/zoneTraffic.json b/plugins/Cloudflare/v2/dataStreams/zoneTraffic.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/zoneTraffic.json rename to plugins/Cloudflare/v2/dataStreams/zoneTraffic.json diff --git a/plugins/Cloudflare/v1/dataStreams/zoneTrafficBreakdown.json b/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/zoneTrafficBreakdown.json rename to plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json diff --git a/plugins/Cloudflare/v1/dataStreams/zones.json b/plugins/Cloudflare/v2/dataStreams/zones.json similarity index 100% rename from plugins/Cloudflare/v1/dataStreams/zones.json rename to plugins/Cloudflare/v2/dataStreams/zones.json diff --git a/plugins/Cloudflare/v1/defaultContent/AI/aiGateway.dash.json b/plugins/Cloudflare/v2/defaultContent/AI/aiGateway.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/AI/aiGateway.dash.json rename to plugins/Cloudflare/v2/defaultContent/AI/aiGateway.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/AI/autorag.dash.json b/plugins/Cloudflare/v2/defaultContent/AI/autorag.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/AI/autorag.dash.json rename to plugins/Cloudflare/v2/defaultContent/AI/autorag.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/AI/manifest.json b/plugins/Cloudflare/v2/defaultContent/AI/manifest.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/AI/manifest.json rename to plugins/Cloudflare/v2/defaultContent/AI/manifest.json diff --git a/plugins/Cloudflare/v1/defaultContent/AI/vectorizeIndex.dash.json b/plugins/Cloudflare/v2/defaultContent/AI/vectorizeIndex.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/AI/vectorizeIndex.dash.json rename to plugins/Cloudflare/v2/defaultContent/AI/vectorizeIndex.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Compute/containerApplication.dash.json b/plugins/Cloudflare/v2/defaultContent/Compute/containerApplication.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Compute/containerApplication.dash.json rename to plugins/Cloudflare/v2/defaultContent/Compute/containerApplication.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Compute/durableObjectNamespace.dash.json b/plugins/Cloudflare/v2/defaultContent/Compute/durableObjectNamespace.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Compute/durableObjectNamespace.dash.json rename to plugins/Cloudflare/v2/defaultContent/Compute/durableObjectNamespace.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Compute/manifest.json b/plugins/Cloudflare/v2/defaultContent/Compute/manifest.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Compute/manifest.json rename to plugins/Cloudflare/v2/defaultContent/Compute/manifest.json diff --git a/plugins/Cloudflare/v1/defaultContent/Compute/pagesProject.dash.json b/plugins/Cloudflare/v2/defaultContent/Compute/pagesProject.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Compute/pagesProject.dash.json rename to plugins/Cloudflare/v2/defaultContent/Compute/pagesProject.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Compute/pipeline.dash.json b/plugins/Cloudflare/v2/defaultContent/Compute/pipeline.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Compute/pipeline.dash.json rename to plugins/Cloudflare/v2/defaultContent/Compute/pipeline.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Compute/queue.dash.json b/plugins/Cloudflare/v2/defaultContent/Compute/queue.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Compute/queue.dash.json rename to plugins/Cloudflare/v2/defaultContent/Compute/queue.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Compute/worker.dash.json b/plugins/Cloudflare/v2/defaultContent/Compute/worker.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Compute/worker.dash.json rename to plugins/Cloudflare/v2/defaultContent/Compute/worker.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Core/account.dash.json b/plugins/Cloudflare/v2/defaultContent/Core/account.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Core/account.dash.json rename to plugins/Cloudflare/v2/defaultContent/Core/account.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Core/manifest.json b/plugins/Cloudflare/v2/defaultContent/Core/manifest.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Core/manifest.json rename to plugins/Cloudflare/v2/defaultContent/Core/manifest.json diff --git a/plugins/Cloudflare/v1/defaultContent/Core/zone.dash.json b/plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Core/zone.dash.json rename to plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Media/manifest.json b/plugins/Cloudflare/v2/defaultContent/Media/manifest.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Media/manifest.json rename to plugins/Cloudflare/v2/defaultContent/Media/manifest.json diff --git a/plugins/Cloudflare/v1/defaultContent/Media/realtimeApp.dash.json b/plugins/Cloudflare/v2/defaultContent/Media/realtimeApp.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Media/realtimeApp.dash.json rename to plugins/Cloudflare/v2/defaultContent/Media/realtimeApp.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Media/streamVideo.dash.json b/plugins/Cloudflare/v2/defaultContent/Media/streamVideo.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Media/streamVideo.dash.json rename to plugins/Cloudflare/v2/defaultContent/Media/streamVideo.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Storage & Databases/d1Database.dash.json b/plugins/Cloudflare/v2/defaultContent/Storage & Databases/d1Database.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Storage & Databases/d1Database.dash.json rename to plugins/Cloudflare/v2/defaultContent/Storage & Databases/d1Database.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Storage & Databases/hyperdriveConfig.dash.json b/plugins/Cloudflare/v2/defaultContent/Storage & Databases/hyperdriveConfig.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Storage & Databases/hyperdriveConfig.dash.json rename to plugins/Cloudflare/v2/defaultContent/Storage & Databases/hyperdriveConfig.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Storage & Databases/kvNamespace.dash.json b/plugins/Cloudflare/v2/defaultContent/Storage & Databases/kvNamespace.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Storage & Databases/kvNamespace.dash.json rename to plugins/Cloudflare/v2/defaultContent/Storage & Databases/kvNamespace.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Storage & Databases/manifest.json b/plugins/Cloudflare/v2/defaultContent/Storage & Databases/manifest.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Storage & Databases/manifest.json rename to plugins/Cloudflare/v2/defaultContent/Storage & Databases/manifest.json diff --git a/plugins/Cloudflare/v1/defaultContent/Storage & Databases/r2Bucket.dash.json b/plugins/Cloudflare/v2/defaultContent/Storage & Databases/r2Bucket.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Storage & Databases/r2Bucket.dash.json rename to plugins/Cloudflare/v2/defaultContent/Storage & Databases/r2Bucket.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Traffic/loadBalancerPool.dash.json b/plugins/Cloudflare/v2/defaultContent/Traffic/loadBalancerPool.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Traffic/loadBalancerPool.dash.json rename to plugins/Cloudflare/v2/defaultContent/Traffic/loadBalancerPool.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Traffic/manifest.json b/plugins/Cloudflare/v2/defaultContent/Traffic/manifest.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Traffic/manifest.json rename to plugins/Cloudflare/v2/defaultContent/Traffic/manifest.json diff --git a/plugins/Cloudflare/v1/defaultContent/Zero Trust/accessApplication.dash.json b/plugins/Cloudflare/v2/defaultContent/Zero Trust/accessApplication.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Zero Trust/accessApplication.dash.json rename to plugins/Cloudflare/v2/defaultContent/Zero Trust/accessApplication.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Zero Trust/manifest.json b/plugins/Cloudflare/v2/defaultContent/Zero Trust/manifest.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Zero Trust/manifest.json rename to plugins/Cloudflare/v2/defaultContent/Zero Trust/manifest.json diff --git a/plugins/Cloudflare/v1/defaultContent/Zero Trust/tunnel.dash.json b/plugins/Cloudflare/v2/defaultContent/Zero Trust/tunnel.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Zero Trust/tunnel.dash.json rename to plugins/Cloudflare/v2/defaultContent/Zero Trust/tunnel.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/Zero Trust/turnstileWidget.dash.json b/plugins/Cloudflare/v2/defaultContent/Zero Trust/turnstileWidget.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/Zero Trust/turnstileWidget.dash.json rename to plugins/Cloudflare/v2/defaultContent/Zero Trust/turnstileWidget.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/manifest.json b/plugins/Cloudflare/v2/defaultContent/manifest.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/manifest.json rename to plugins/Cloudflare/v2/defaultContent/manifest.json diff --git a/plugins/Cloudflare/v1/defaultContent/overview.dash.json b/plugins/Cloudflare/v2/defaultContent/overview.dash.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/overview.dash.json rename to plugins/Cloudflare/v2/defaultContent/overview.dash.json diff --git a/plugins/Cloudflare/v1/defaultContent/scopes.json b/plugins/Cloudflare/v2/defaultContent/scopes.json similarity index 100% rename from plugins/Cloudflare/v1/defaultContent/scopes.json rename to plugins/Cloudflare/v2/defaultContent/scopes.json diff --git a/plugins/Cloudflare/v1/docs/README.md b/plugins/Cloudflare/v2/docs/README.md similarity index 100% rename from plugins/Cloudflare/v1/docs/README.md rename to plugins/Cloudflare/v2/docs/README.md diff --git a/plugins/Cloudflare/v1/icon.svg b/plugins/Cloudflare/v2/icon.svg similarity index 100% rename from plugins/Cloudflare/v1/icon.svg rename to plugins/Cloudflare/v2/icon.svg diff --git a/plugins/Cloudflare/v1/indexDefinitions/default.json b/plugins/Cloudflare/v2/indexDefinitions/default.json similarity index 100% rename from plugins/Cloudflare/v1/indexDefinitions/default.json rename to plugins/Cloudflare/v2/indexDefinitions/default.json diff --git a/plugins/Cloudflare/v1/metadata.json b/plugins/Cloudflare/v2/metadata.json similarity index 97% rename from plugins/Cloudflare/v1/metadata.json rename to plugins/Cloudflare/v2/metadata.json index 5ce3dca8..c93c4954 100644 --- a/plugins/Cloudflare/v1/metadata.json +++ b/plugins/Cloudflare/v2/metadata.json @@ -1,7 +1,7 @@ { "name": "cloudflare", "displayName": "Cloudflare", - "version": "1.0.0", + "version": "2.0.0", "author": { "name": "@clarkd", "type": "community" @@ -72,7 +72,7 @@ "links": [ { "category": "documentation", - "url": "https://github.com/squaredup/plugins/blob/main/plugins/Cloudflare/v1/docs/README.md", + "url": "https://github.com/squaredup/plugins/blob/main/plugins/Cloudflare/v2/docs/README.md", "label": "Help adding this plugin" }, { diff --git a/plugins/Cloudflare/v1/ui.json b/plugins/Cloudflare/v2/ui.json similarity index 88% rename from plugins/Cloudflare/v1/ui.json rename to plugins/Cloudflare/v2/ui.json index 3698b831..9cfb68fc 100644 --- a/plugins/Cloudflare/v1/ui.json +++ b/plugins/Cloudflare/v2/ui.json @@ -4,7 +4,7 @@ "name": "apiToken", "label": "API token", "placeholder": "Enter the Cloudflare API token", - "help": "Create a custom token at [My Profile → API Tokens](https://dash.cloudflare.com/profile/api-tokens) with **Read** access to the accounts, zones and products you want to monitor - the [setup guide](https://github.com/squaredup/plugins/blob/main/plugins/Cloudflare/v1/docs/README.md) lists the exact permissions. Legacy Global API Keys are not supported.", + "help": "Create a custom token at [My Profile → API Tokens](https://dash.cloudflare.com/profile/api-tokens) with **Read** access to the accounts, zones and products you want to monitor - the [setup guide](https://github.com/squaredup/plugins/blob/main/plugins/Cloudflare/v2/docs/README.md) lists the exact permissions. Legacy Global API Keys are not supported.", "validation": { "required": true } } ] From d8a38c677c022969616376df77d06dd8b6fd5ae4 Mon Sep 17 00:00:00 2001 From: Dave Clarke Date: Wed, 19 Aug 2026 10:31:10 +0100 Subject: [PATCH 06/27] Document that the first import only populates accounts and zones On a brand new data source, the steps that import child resources run against accounts and zones the same import has just created, and those objects are not yet visible to their scope queries. The steps are skipped with a warning and the next import picks them all up. Verified against a fresh install: the first import wrote 2 accounts and 8 zones but 18 of 21 dependent steps issued no request; an immediate second import ran every step and wrote 10 Workers, 8 Worker Routes, 6 Stream Videos and the rest. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01CXgffao5bcMhNz3Ci7eCi9 --- plugins/Cloudflare/v2/docs/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/Cloudflare/v2/docs/README.md b/plugins/Cloudflare/v2/docs/README.md index 24ae2722..6dbfcbf8 100644 --- a/plugins/Cloudflare/v2/docs/README.md +++ b/plugins/Cloudflare/v2/docs/README.md @@ -213,5 +213,6 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w - **A failed Cloudflare query can look like "no data".** Cloudflare answers a failed GraphQL query with HTTP 200 and an `errors` array, which the platform does not treat as a failure. Streams that use a post-request script raise these errors explicitly, but the simpler declarative streams will show an empty tile instead of an error message. - **Costs are unitless.** Cloudflare's AI Gateway analytics reports cost without stating a currency, so the plugin shows a plain number rather than assuming one. - **Pages Functions cannot be scoped to a single project.** Cloudflare identifies Pages Functions by an internal script name with no published mapping to the project, so this stream reports all Pages Functions in the account, with the function name as a column. +- **The first import only populates accounts and zones.** Everything below them - Workers, KV namespaces, queues, tunnels, Stream videos, Turnstile widgets and the rest - is imported by steps that run against the accounts and zones the same import has just created, and on a brand new data source those objects are not yet visible when those steps start. They are skipped with a warning, and the **next import picks them all up**. Trigger a re-import from the data source page after adding the plugin rather than waiting for the scheduled one. - **Imports run every 12 hours** by default, so newly created zones and resources are not visible immediately. - **Read-only.** The plugin never creates, modifies or deletes anything in Cloudflare. From ea213ccfa0c1b22e803dbd953f4c80d8c57f6f45 Mon Sep 17 00:00:00 2001 From: Dave Clarke Date: Wed, 19 Aug 2026 10:45:58 +0100 Subject: [PATCH 07/27] Add four correlation rules and make Turnstile domains an array - Durable Object Namespace defined by Worker (scriptName -> Worker name) - Turnstile Widget protects Zone (domains -> Zone name) - Worker Route on Zone (zoneId -> Zone rawId) - Worker Route handled by Worker (scriptName -> Worker name) Worker Route previously had no edges at all: it carries zoneId and scriptName but not accountId, so it was excluded from the account containment rule, and the Worker-serves-Zone bridge connects its endpoints without connecting the route itself. turnstileWidgets.js now emits domains as an array rather than a joined string, matching pagesProjects.js, so the Zone rule can match any element. The one widget in the test account carries squaredup.com, which is an imported zone, so this rule doubles as a live test of whether correlation matches array-valued properties at all - the two existing array-based rules (Pages Project -> Zone, Queue -> Worker) have no matching data to prove it. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01CXgffao5bcMhNz3Ci7eCi9 --- ...te-durable-object-namespace-to-worker.json | 20 +++++++++++++++++++ .../relate-turnstile-widget-to-zone.json | 20 +++++++++++++++++++ .../relate-worker-route-to-worker.json | 20 +++++++++++++++++++ .../relate-worker-route-to-zone.json | 20 +++++++++++++++++++ .../dataStreams/scripts/turnstileWidgets.js | 5 ++++- 5 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 plugins/Cloudflare/v2/correlationRules/relate-durable-object-namespace-to-worker.json create mode 100644 plugins/Cloudflare/v2/correlationRules/relate-turnstile-widget-to-zone.json create mode 100644 plugins/Cloudflare/v2/correlationRules/relate-worker-route-to-worker.json create mode 100644 plugins/Cloudflare/v2/correlationRules/relate-worker-route-to-zone.json diff --git a/plugins/Cloudflare/v2/correlationRules/relate-durable-object-namespace-to-worker.json b/plugins/Cloudflare/v2/correlationRules/relate-durable-object-namespace-to-worker.json new file mode 100644 index 00000000..c9f9db9e --- /dev/null +++ b/plugins/Cloudflare/v2/correlationRules/relate-durable-object-namespace-to-worker.json @@ -0,0 +1,20 @@ +{ + "displayName": "Durable Object Namespace defined by Worker", + "source": { + "types": "Cloudflare Durable Object Namespace" + }, + "target": { + "types": "Cloudflare Worker" + }, + "conditions": [ + { + "sourceProperty": "scriptName", + "operator": "equals", + "targetProperty": "name" + } + ], + "labels": { + "forward": "defined by", + "reverse": "defines" + } +} diff --git a/plugins/Cloudflare/v2/correlationRules/relate-turnstile-widget-to-zone.json b/plugins/Cloudflare/v2/correlationRules/relate-turnstile-widget-to-zone.json new file mode 100644 index 00000000..020ae405 --- /dev/null +++ b/plugins/Cloudflare/v2/correlationRules/relate-turnstile-widget-to-zone.json @@ -0,0 +1,20 @@ +{ + "displayName": "Turnstile Widget protects Zone", + "source": { + "types": "Cloudflare Turnstile Widget" + }, + "target": { + "types": "Cloudflare Zone" + }, + "conditions": [ + { + "sourceProperty": "domains", + "operator": "equals", + "targetProperty": "name" + } + ], + "labels": { + "forward": "protects", + "reverse": "protected by" + } +} diff --git a/plugins/Cloudflare/v2/correlationRules/relate-worker-route-to-worker.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-route-to-worker.json new file mode 100644 index 00000000..ec69301b --- /dev/null +++ b/plugins/Cloudflare/v2/correlationRules/relate-worker-route-to-worker.json @@ -0,0 +1,20 @@ +{ + "displayName": "Worker Route handled by Worker", + "source": { + "types": "Cloudflare Worker Route" + }, + "target": { + "types": "Cloudflare Worker" + }, + "conditions": [ + { + "sourceProperty": "scriptName", + "operator": "equals", + "targetProperty": "name" + } + ], + "labels": { + "forward": "handled by", + "reverse": "handles" + } +} diff --git a/plugins/Cloudflare/v2/correlationRules/relate-worker-route-to-zone.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-route-to-zone.json new file mode 100644 index 00000000..85ba711c --- /dev/null +++ b/plugins/Cloudflare/v2/correlationRules/relate-worker-route-to-zone.json @@ -0,0 +1,20 @@ +{ + "displayName": "Worker Route on Zone", + "source": { + "types": "Cloudflare Worker Route" + }, + "target": { + "types": "Cloudflare Zone" + }, + "conditions": [ + { + "sourceProperty": "zoneId", + "operator": "equals", + "targetProperty": "rawId" + } + ], + "labels": { + "forward": "routes traffic on", + "reverse": "has route" + } +} diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/turnstileWidgets.js b/plugins/Cloudflare/v2/dataStreams/scripts/turnstileWidgets.js index 6efa14dc..e35b4f3e 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/turnstileWidgets.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/turnstileWidgets.js @@ -9,7 +9,10 @@ result = ((data && data.result) || []).map((w) => ({ accountId: accountId, mode: w.mode || "", region: w.region || "", - domains: (w.domains || []).join(", "), + // Kept as an array, not a joined string: it is the join key for the + // Turnstile Widget -> Zone correlation rule, and correlation matches an + // array property if any element matches. + domains: w.domains || [], botFightMode: Boolean(w.bot_fight_mode), createdOn: w.created_on, modifiedOn: w.modified_on, From f5e6d203a26ddd209787d3ffc117cbbbd5265a91 Mon Sep 17 00:00:00 2001 From: Dave Clarke Date: Wed, 19 Aug 2026 10:50:59 +0100 Subject: [PATCH 08/27] Add three more correlation rules across bindings, queues and Access - Worker Binding calls Worker (serviceName -> Worker name), so a service binding links the two Workers it connects. The property was already captured and mapped, so this needed no re-import. - Queue produced to by Worker (producerScripts -> Worker name), mirroring the existing consumer rule. queues.js now emits producerScripts. - Access Application protects Zone, deriving the registrable domain from the app's hostname with a sourceExpression, since an Access app sits on a subdomain rather than the zone apex. A derivation that guesses wrong yields a key matching no zone, so it produces no edge rather than a wrong one. Nothing further is joinable for Media (Stream videos and Realtime apps carry no property referencing another Cloudflare object), AI (the AutoRAG list endpoint does not return the Vectorize index it uses) or Storage (already covered by the Worker Binding rules). Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01CXgffao5bcMhNz3Ci7eCi9 --- .../relate-access-application-to-zone.json | 21 +++++++++++++++++++ .../relate-queue-to-producer-worker.json | 20 ++++++++++++++++++ ...late-worker-binding-to-service-worker.json | 20 ++++++++++++++++++ plugins/Cloudflare/v2/dataStreams/queues.json | 5 +++++ .../v2/dataStreams/scripts/queues.js | 4 ++++ .../v2/indexDefinitions/default.json | 3 ++- 6 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 plugins/Cloudflare/v2/correlationRules/relate-access-application-to-zone.json create mode 100644 plugins/Cloudflare/v2/correlationRules/relate-queue-to-producer-worker.json create mode 100644 plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-service-worker.json diff --git a/plugins/Cloudflare/v2/correlationRules/relate-access-application-to-zone.json b/plugins/Cloudflare/v2/correlationRules/relate-access-application-to-zone.json new file mode 100644 index 00000000..9fd82783 --- /dev/null +++ b/plugins/Cloudflare/v2/correlationRules/relate-access-application-to-zone.json @@ -0,0 +1,21 @@ +{ + "displayName": "Access Application protects Zone", + "source": { + "types": "Cloudflare Access Application" + }, + "target": { + "types": "Cloudflare Zone" + }, + "conditions": [ + { + "sourceProperty": "domain", + "sourceExpression": "{{ value.split('.').slice(-2).join('.') }}", + "operator": "equals", + "targetProperty": "name" + } + ], + "labels": { + "forward": "protects", + "reverse": "protected by" + } +} diff --git a/plugins/Cloudflare/v2/correlationRules/relate-queue-to-producer-worker.json b/plugins/Cloudflare/v2/correlationRules/relate-queue-to-producer-worker.json new file mode 100644 index 00000000..d73415e5 --- /dev/null +++ b/plugins/Cloudflare/v2/correlationRules/relate-queue-to-producer-worker.json @@ -0,0 +1,20 @@ +{ + "displayName": "Queue produced to by Worker", + "source": { + "types": "Cloudflare Queue" + }, + "target": { + "types": "Cloudflare Worker" + }, + "conditions": [ + { + "sourceProperty": "producerScripts", + "operator": "equals", + "targetProperty": "name" + } + ], + "labels": { + "forward": "produced to by", + "reverse": "produces to" + } +} diff --git a/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-service-worker.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-service-worker.json new file mode 100644 index 00000000..8a172a72 --- /dev/null +++ b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-service-worker.json @@ -0,0 +1,20 @@ +{ + "displayName": "Worker Binding calls Worker", + "source": { + "types": "Cloudflare Worker Binding" + }, + "target": { + "types": "Cloudflare Worker" + }, + "conditions": [ + { + "sourceProperty": "serviceName", + "operator": "equals", + "targetProperty": "name" + } + ], + "labels": { + "forward": "calls", + "reverse": "called by" + } +} diff --git a/plugins/Cloudflare/v2/dataStreams/queues.json b/plugins/Cloudflare/v2/dataStreams/queues.json index ca9cfc11..b7bd794f 100644 --- a/plugins/Cloudflare/v2/dataStreams/queues.json +++ b/plugins/Cloudflare/v2/dataStreams/queues.json @@ -74,6 +74,11 @@ "name": "consumerScripts", "displayName": "Consumer Workers", "shape": "string" + }, + { + "name": "producerScripts", + "displayName": "Producer Workers", + "shape": "string" } ], "timeframes": false diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/queues.js b/plugins/Cloudflare/v2/dataStreams/scripts/queues.js index 4841e9c1..42e3ff7e 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/queues.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/queues.js @@ -22,6 +22,10 @@ result = ((data && data.result) || []).map((queue) => ({ consumerScripts: (queue.consumers || []) .map((c) => c && c.service) .filter(Boolean), + // The producing Worker script names, same join-key reasoning as consumers. + producerScripts: (queue.producers || []) + .map((p) => p && p.script) + .filter(Boolean), createdOn: queue.created_on, modifiedOn: queue.modified_on, })); diff --git a/plugins/Cloudflare/v2/indexDefinitions/default.json b/plugins/Cloudflare/v2/indexDefinitions/default.json index 677775ab..be563c17 100644 --- a/plugins/Cloudflare/v2/indexDefinitions/default.json +++ b/plugins/Cloudflare/v2/indexDefinitions/default.json @@ -227,7 +227,8 @@ "consumers", "createdOn", "modifiedOn", - "consumerScripts" + "consumerScripts", + "producerScripts" ] } }, From 792be65f830232481c180c8469b76774ba94be29 Mon Sep 17 00:00:00 2001 From: Dave Clarke Date: Wed, 19 Aug 2026 10:56:24 +0100 Subject: [PATCH 09/27] Document the seven correlation rules missing from the README The relationships table listed 12 of the 19 rules the plugin now ships, having not been updated as rules were added. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01CXgffao5bcMhNz3Ci7eCi9 --- plugins/Cloudflare/v2/docs/README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/Cloudflare/v2/docs/README.md b/plugins/Cloudflare/v2/docs/README.md index 6dbfcbf8..2eff0d75 100644 --- a/plugins/Cloudflare/v2/docs/README.md +++ b/plugins/Cloudflare/v2/docs/README.md @@ -172,9 +172,14 @@ Cloudflare's GraphQL Analytics API exposes far more datasets than this plugin sh | ------------ | -------------- | | Every resource **belongs to** its Account | the resource's `accountId` against the account's id | | Worker Binding **declared by** Worker, and **targets** the KV namespace / R2 bucket / D1 database / queue / Durable Object namespace / Vectorize index / Hyperdrive config it points at | the binding's target id against that resource's id | +| Worker Binding **calls** Worker | a service binding's target script name against the Worker name | | Worker **serves** Zone | through the Worker Route that names both | +| Worker Route **routes to** Worker, and **belongs to** Zone | the route's script name and zone id | +| Durable Object Namespace **implemented by** Worker | the namespace's script name against the Worker name | | Pages Project **served by** Zone | the project's custom domains against the zone name | -| Queue **consumed by** Worker | the queue's consumer script names against the Worker name | +| Queue **consumed by** Worker, and **produced to by** Worker | the queue's consumer and producer script names against the Worker name | +| Turnstile Widget **protects** Zone | the widget's allowed domains against the zone name | +| Access Application **protects** Zone | the registrable domain derived from the app's hostname against the zone name | Together these give a dependency graph: from a KV namespace you can see which Workers bind it, and from a Worker which zones it serves. From 43536de7cec995589ca15309c571a991473f1bfc Mon Sep 17 00:00:00 2001 From: Dave Clarke Date: Wed, 19 Aug 2026 11:19:59 +0100 Subject: [PATCH 10/27] Correlate one-to-many relationships on a scalar, not an array Four rules joined on an array property - Turnstile widget domains, Pages project domains, and queue consumer and producer scripts - on the assumption that correlation matches an array if any element matches. It does not, and the array never reaches correlation in the first place: the import serialises it to a JSON string, so the stored value was the literal ["squaredup.com"] and could never equal a zone named squaredup.com. All four rules were silently dead. Verified by importing the same array twice, once declared shape "string" and once with no shape at all; both landed as the identical JSON string, so the shape declaration is not the cause. Scalars keep their type, arrays do not. Correlation offers only `equals`, so there is no operator that can match into a serialised list. Each affected stream now emits the full list as a comma-separated string for display plus a primary* scalar holding the first entry, and the rules join on that - the same approach Kubernetes takes with primaryBackendServiceName. A source naming several targets now draws one edge rather than none. Documented under Known limitations. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01CXgffao5bcMhNz3Ci7eCi9 --- .../relate-pages-project-to-zone.json | 2 +- .../relate-queue-to-producer-worker.json | 2 +- .../v2/correlationRules/relate-queue-to-worker.json | 2 +- .../relate-turnstile-widget-to-zone.json | 2 +- plugins/Cloudflare/v2/dataStreams/pagesProjects.json | 5 +++++ plugins/Cloudflare/v2/dataStreams/queues.json | 10 ++++++++++ .../v2/dataStreams/scripts/pagesProjects.js | 3 ++- plugins/Cloudflare/v2/dataStreams/scripts/queues.js | 12 ++++++++++-- .../v2/dataStreams/scripts/turnstileWidgets.js | 9 +++++---- .../Cloudflare/v2/dataStreams/turnstileWidgets.json | 5 +++++ plugins/Cloudflare/v2/docs/README.md | 8 +++++--- plugins/Cloudflare/v2/indexDefinitions/default.json | 6 +++++- 12 files changed, 51 insertions(+), 15 deletions(-) diff --git a/plugins/Cloudflare/v2/correlationRules/relate-pages-project-to-zone.json b/plugins/Cloudflare/v2/correlationRules/relate-pages-project-to-zone.json index b4aacfa3..5ca1cf7f 100644 --- a/plugins/Cloudflare/v2/correlationRules/relate-pages-project-to-zone.json +++ b/plugins/Cloudflare/v2/correlationRules/relate-pages-project-to-zone.json @@ -8,7 +8,7 @@ }, "conditions": [ { - "sourceProperty": "domains", + "sourceProperty": "primaryDomain", "operator": "equals", "targetProperty": "name" } diff --git a/plugins/Cloudflare/v2/correlationRules/relate-queue-to-producer-worker.json b/plugins/Cloudflare/v2/correlationRules/relate-queue-to-producer-worker.json index d73415e5..6116bd5b 100644 --- a/plugins/Cloudflare/v2/correlationRules/relate-queue-to-producer-worker.json +++ b/plugins/Cloudflare/v2/correlationRules/relate-queue-to-producer-worker.json @@ -8,7 +8,7 @@ }, "conditions": [ { - "sourceProperty": "producerScripts", + "sourceProperty": "primaryProducerScript", "operator": "equals", "targetProperty": "name" } diff --git a/plugins/Cloudflare/v2/correlationRules/relate-queue-to-worker.json b/plugins/Cloudflare/v2/correlationRules/relate-queue-to-worker.json index 56ed2652..0783bde9 100644 --- a/plugins/Cloudflare/v2/correlationRules/relate-queue-to-worker.json +++ b/plugins/Cloudflare/v2/correlationRules/relate-queue-to-worker.json @@ -8,7 +8,7 @@ }, "conditions": [ { - "sourceProperty": "consumerScripts", + "sourceProperty": "primaryConsumerScript", "operator": "equals", "targetProperty": "name" } diff --git a/plugins/Cloudflare/v2/correlationRules/relate-turnstile-widget-to-zone.json b/plugins/Cloudflare/v2/correlationRules/relate-turnstile-widget-to-zone.json index 020ae405..2740cb18 100644 --- a/plugins/Cloudflare/v2/correlationRules/relate-turnstile-widget-to-zone.json +++ b/plugins/Cloudflare/v2/correlationRules/relate-turnstile-widget-to-zone.json @@ -8,7 +8,7 @@ }, "conditions": [ { - "sourceProperty": "domains", + "sourceProperty": "primaryDomain", "operator": "equals", "targetProperty": "name" } diff --git a/plugins/Cloudflare/v2/dataStreams/pagesProjects.json b/plugins/Cloudflare/v2/dataStreams/pagesProjects.json index ebc6bdde..4cb04ead 100644 --- a/plugins/Cloudflare/v2/dataStreams/pagesProjects.json +++ b/plugins/Cloudflare/v2/dataStreams/pagesProjects.json @@ -77,6 +77,11 @@ "displayName": "Domains", "shape": "string" }, + { + "name": "primaryDomain", + "displayName": "Primary Domain", + "shape": "string" + }, { "name": "productionBranch", "displayName": "Production Branch", diff --git a/plugins/Cloudflare/v2/dataStreams/queues.json b/plugins/Cloudflare/v2/dataStreams/queues.json index b7bd794f..fd579815 100644 --- a/plugins/Cloudflare/v2/dataStreams/queues.json +++ b/plugins/Cloudflare/v2/dataStreams/queues.json @@ -75,10 +75,20 @@ "displayName": "Consumer Workers", "shape": "string" }, + { + "name": "primaryConsumerScript", + "displayName": "Primary Consumer", + "shape": "string" + }, { "name": "producerScripts", "displayName": "Producer Workers", "shape": "string" + }, + { + "name": "primaryProducerScript", + "displayName": "Primary Producer", + "shape": "string" } ], "timeframes": false diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/pagesProjects.js b/plugins/Cloudflare/v2/dataStreams/scripts/pagesProjects.js index c14ea26e..dda18f35 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/pagesProjects.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/pagesProjects.js @@ -14,7 +14,8 @@ result = ((data && data.result) || []).map((project) => { // Kept as an array, not a joined string: it is the join key for the // Pages Project -> Zone correlation rule, and correlation matches an // array property if any element matches. - domains: project.domains || [], + domains: (project.domains || []).join(", "), + primaryDomain: (project.domains || [])[0] || "", productionBranch: project.production_branch || "", latestDeploymentStatus: stage.status || "", latestDeploymentOn: latest.modified_on || latest.created_on, diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/queues.js b/plugins/Cloudflare/v2/dataStreams/scripts/queues.js index 42e3ff7e..a14493e3 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/queues.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/queues.js @@ -21,11 +21,19 @@ result = ((data && data.result) || []).map((queue) => ({ // no service name and are filtered out. consumerScripts: (queue.consumers || []) .map((c) => c && c.service) - .filter(Boolean), + .filter(Boolean) + .join(", "), + primaryConsumerScript: + ((queue.consumers || []).map((c) => c && c.service).filter(Boolean))[0] || + "", // The producing Worker script names, same join-key reasoning as consumers. producerScripts: (queue.producers || []) .map((p) => p && p.script) - .filter(Boolean), + .filter(Boolean) + .join(", "), + primaryProducerScript: + ((queue.producers || []).map((p) => p && p.script).filter(Boolean))[0] || + "", createdOn: queue.created_on, modifiedOn: queue.modified_on, })); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/turnstileWidgets.js b/plugins/Cloudflare/v2/dataStreams/scripts/turnstileWidgets.js index e35b4f3e..7ce07a05 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/turnstileWidgets.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/turnstileWidgets.js @@ -9,10 +9,11 @@ result = ((data && data.result) || []).map((w) => ({ accountId: accountId, mode: w.mode || "", region: w.region || "", - // Kept as an array, not a joined string: it is the join key for the - // Turnstile Widget -> Zone correlation rule, and correlation matches an - // array property if any element matches. - domains: w.domains || [], + // Two columns, because the import serialises an array property to a JSON + // string and correlation can only compare scalars: `domains` is for display + // and `primaryDomain` is the join key for the Turnstile Widget -> Zone rule. + domains: (w.domains || []).join(", "), + primaryDomain: (w.domains || [])[0] || "", botFightMode: Boolean(w.bot_fight_mode), createdOn: w.created_on, modifiedOn: w.modified_on, diff --git a/plugins/Cloudflare/v2/dataStreams/turnstileWidgets.json b/plugins/Cloudflare/v2/dataStreams/turnstileWidgets.json index e3b86cc0..5cf285e9 100644 --- a/plugins/Cloudflare/v2/dataStreams/turnstileWidgets.json +++ b/plugins/Cloudflare/v2/dataStreams/turnstileWidgets.json @@ -65,6 +65,11 @@ "displayName": "Domains", "shape": "string" }, + { + "name": "primaryDomain", + "displayName": "Primary Domain", + "shape": "string" + }, { "name": "botFightMode", "displayName": "Bot Fight Mode", diff --git a/plugins/Cloudflare/v2/docs/README.md b/plugins/Cloudflare/v2/docs/README.md index 2eff0d75..3159e07c 100644 --- a/plugins/Cloudflare/v2/docs/README.md +++ b/plugins/Cloudflare/v2/docs/README.md @@ -176,9 +176,9 @@ Cloudflare's GraphQL Analytics API exposes far more datasets than this plugin sh | Worker **serves** Zone | through the Worker Route that names both | | Worker Route **routes to** Worker, and **belongs to** Zone | the route's script name and zone id | | Durable Object Namespace **implemented by** Worker | the namespace's script name against the Worker name | -| Pages Project **served by** Zone | the project's custom domains against the zone name | -| Queue **consumed by** Worker, and **produced to by** Worker | the queue's consumer and producer script names against the Worker name | -| Turnstile Widget **protects** Zone | the widget's allowed domains against the zone name | +| Pages Project **served by** Zone | the project's first custom domain against the zone name | +| Queue **consumed by** Worker, and **produced to by** Worker | the queue's first consumer and first producer script name against the Worker name | +| Turnstile Widget **protects** Zone | the widget's first allowed domain against the zone name | | Access Application **protects** Zone | the registrable domain derived from the app's hostname against the zone name | Together these give a dependency graph: from a KV namespace you can see which Workers bind it, and from a Worker which zones it serves. @@ -187,6 +187,8 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w ## Known limitations +- **One-to-many relationships only correlate on their first value.** The import serialises an array-valued property to a JSON string (`["a.com","b.com"]`) rather than storing it as a multi-valued property, and correlation conditions only offer `equals`, so an array can never match a scalar. Where a Cloudflare object names several others - a Turnstile widget's allowed domains, a Pages project's custom domains, a queue's consumers and producers - the plugin stores the full list as a readable string for display and a separate `primary*` property holding the first entry, and correlates on that. A widget covering three zones therefore draws an edge to one of them. The same constraint is why Kubernetes, the only other plugin here shipping correlation rules, joins on `primaryBackendServiceName` rather than the full backend list. + - **Analytics timeframes are capped per dataset, and the caps are short.** Cloudflare's GraphQL Analytics API limits how wide a single query's time range can be, and the limit differs for every dataset. These were measured against a Pro-plan account: | Widest single query | Data streams | diff --git a/plugins/Cloudflare/v2/indexDefinitions/default.json b/plugins/Cloudflare/v2/indexDefinitions/default.json index be563c17..2045ea1f 100644 --- a/plugins/Cloudflare/v2/indexDefinitions/default.json +++ b/plugins/Cloudflare/v2/indexDefinitions/default.json @@ -142,6 +142,7 @@ "accountId", "subdomain", "domains", + "primaryDomain", "productionBranch", "latestDeploymentStatus", "latestDeploymentOn", @@ -228,7 +229,9 @@ "createdOn", "modifiedOn", "consumerScripts", - "producerScripts" + "primaryConsumerScript", + "producerScripts", + "primaryProducerScript" ] } }, @@ -517,6 +520,7 @@ "mode", "region", "domains", + "primaryDomain", "botFightMode", "createdOn", "modifiedOn" From 85fa486bb2e713bae4c83572e5b450a3ee561cfb Mon Sep 17 00:00:00 2001 From: Dave Clarke Date: Wed, 19 Aug 2026 11:32:09 +0100 Subject: [PATCH 11/27] Render a zone's name servers as a readable list name_servers was the last array-valued column left, and it reached tiles and the Zone's property panel as the raw JSON ["a.ns...","b.ns..."]. It feeds no correlation rule, so this was cosmetic rather than a dead edge, but it is the same underlying behaviour. The raw column is now hidden and a computed nameServers column unpicks it. Unpicked with split/join rather than JSON.parse, which throws on the empty string a zone with no name servers yields. A regex literal was tried first and silently does not work in a valueExpression - the brackets and quotes survived it - so the chain is deliberate, not clumsiness. Swept every other stream while here: no script assigns an array to a column, and DNS record tags arrive as an empty string rather than [], so nothing else is affected. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01CXgffao5bcMhNz3Ci7eCi9 --- plugins/Cloudflare/v2/dataStreams/zones.json | 10 +++++++++- plugins/Cloudflare/v2/indexDefinitions/default.json | 4 +--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/plugins/Cloudflare/v2/dataStreams/zones.json b/plugins/Cloudflare/v2/dataStreams/zones.json index b1239fc5..6be346f5 100644 --- a/plugins/Cloudflare/v2/dataStreams/zones.json +++ b/plugins/Cloudflare/v2/dataStreams/zones.json @@ -151,7 +151,15 @@ { "name": "name_servers", "displayName": "Name Servers", - "shape": "string" + "shape": "string", + "visible": false + }, + { + "name": "nameServers", + "displayName": "Name Servers", + "computed": true, + "shape": "string", + "valueExpression": "{{ $['name_servers'].split('\"').join('').split('[').join('').split(']').join('').split(',').join(', ') }}" } ], "timeframes": false diff --git a/plugins/Cloudflare/v2/indexDefinitions/default.json b/plugins/Cloudflare/v2/indexDefinitions/default.json index 2045ea1f..c0135ff8 100644 --- a/plugins/Cloudflare/v2/indexDefinitions/default.json +++ b/plugins/Cloudflare/v2/indexDefinitions/default.json @@ -56,9 +56,7 @@ { "activatedOn": "activated_on" }, - { - "nameServers": "name_servers" - } + "nameServers" ] } }, From d1c75db50ad6c690d3cb03dfd7d3ac37a78ef6fc Mon Sep 17 00:00:00 2001 From: Dave Clarke Date: Wed, 19 Aug 2026 12:21:58 +0100 Subject: [PATCH 12/27] Address PR review on the Cloudflare plugin Scope every name-based correlation rule by accountId. Cloudflare only guarantees a Worker, queue, bucket or index name is unique within an account, so a token that can read two accounts drew edges between a resource in one and a same-named Worker in the other. Worker Routes had no accountId at all, so the route mapping now carries it from the zone. Keep the RUM Core Web Vitals quantiles in the milliseconds Cloudflare reports them in, rather than dividing by 1000 and rounding. Drop the duplicated GraphQL error handler from three scripts, where an unconditional first throw made the aggregated handler below it dead. Stop reporting absent load balancer health as unhealthy, and map Stream's -1 duration sentinel to null instead of a real length. Correct the comments in pagesProjects.js and queues.js that still claim the domain and script lists are kept as arrays for correlation; they are joined for display, and the rules correlate on the primary* scalars. Title the 106 scalar tiles, which all shipped with an empty title against a repo convention of titled tiles, and relabel the Realtime peak tile: its rows are per track type per day, so an ungrouped max is not a daily total. Rename the queue producer relationship to describe message flow. Mark the zones index step optional to match configValidation, which already treats zone access as optional, and move the category from CDN to the existing Cloud Platforms. Document the public-suffix gap in Access Application correlation and the 10,000-row cap on per-minute analytics, and remove Stream, Images and Turnstile from the unsupported list - all three are covered. Co-Authored-By: Claude Opus 5 --- ...te-durable-object-namespace-to-worker.json | 5 +++ .../relate-queue-to-producer-worker.json | 11 ++++-- .../relate-queue-to-worker.json | 5 +++ .../relate-worker-binding-to-queue.json | 5 +++ .../relate-worker-binding-to-r2-bucket.json | 5 +++ ...late-worker-binding-to-service-worker.json | 5 +++ ...ate-worker-binding-to-vectorize-index.json | 5 +++ .../relate-worker-binding-to-worker.json | 5 +++ .../relate-worker-route-to-worker.json | 5 +++ .../v2/dataStreams/rumWebVitals.json | 4 +-- .../scripts/dnsFirewallAnalytics.js | 7 ---- .../scripts/loadBalancerPoolHealth.js | 7 ++-- .../v2/dataStreams/scripts/pagesProjects.js | 6 ++-- .../v2/dataStreams/scripts/queues.js | 10 +++--- .../v2/dataStreams/scripts/streamVideos.js | 5 ++- .../v2/dataStreams/scripts/workerRoutes.js | 5 +++ .../v2/dataStreams/scripts/zoneNelReports.js | 7 ---- .../v2/dataStreams/scripts/zonePageShield.js | 7 ---- .../v2/dataStreams/workerRoutes.json | 1 + .../v2/defaultContent/AI/aiGateway.dash.json | 8 ++--- .../v2/defaultContent/AI/autorag.dash.json | 8 ++--- .../AI/vectorizeIndex.dash.json | 8 ++--- .../Compute/containerApplication.dash.json | 8 ++--- .../Compute/durableObjectNamespace.dash.json | 8 ++--- .../defaultContent/Compute/pipeline.dash.json | 8 ++--- .../v2/defaultContent/Compute/queue.dash.json | 8 ++--- .../defaultContent/Compute/worker.dash.json | 8 ++--- .../v2/defaultContent/Core/account.dash.json | 26 +++++++------- .../v2/defaultContent/Core/zone.dash.json | 16 ++++----- .../Media/realtimeApp.dash.json | 10 +++--- .../Media/streamVideo.dash.json | 8 ++--- .../Storage & Databases/d1Database.dash.json | 8 ++--- .../hyperdriveConfig.dash.json | 8 ++--- .../Storage & Databases/kvNamespace.dash.json | 8 ++--- .../Storage & Databases/r2Bucket.dash.json | 8 ++--- .../Traffic/loadBalancerPool.dash.json | 4 +-- .../Zero Trust/accessApplication.dash.json | 8 ++--- .../Zero Trust/tunnel.dash.json | 4 +-- .../Zero Trust/turnstileWidget.dash.json | 8 ++--- .../v2/defaultContent/overview.dash.json | 34 +++++++++---------- plugins/Cloudflare/v2/docs/README.md | 14 +++++--- .../v2/indexDefinitions/default.json | 2 ++ plugins/Cloudflare/v2/metadata.json | 2 +- 43 files changed, 194 insertions(+), 148 deletions(-) diff --git a/plugins/Cloudflare/v2/correlationRules/relate-durable-object-namespace-to-worker.json b/plugins/Cloudflare/v2/correlationRules/relate-durable-object-namespace-to-worker.json index c9f9db9e..bd276682 100644 --- a/plugins/Cloudflare/v2/correlationRules/relate-durable-object-namespace-to-worker.json +++ b/plugins/Cloudflare/v2/correlationRules/relate-durable-object-namespace-to-worker.json @@ -11,6 +11,11 @@ "sourceProperty": "scriptName", "operator": "equals", "targetProperty": "name" + }, + { + "sourceProperty": "accountId", + "operator": "equals", + "targetProperty": "accountId" } ], "labels": { diff --git a/plugins/Cloudflare/v2/correlationRules/relate-queue-to-producer-worker.json b/plugins/Cloudflare/v2/correlationRules/relate-queue-to-producer-worker.json index 6116bd5b..0abb0d75 100644 --- a/plugins/Cloudflare/v2/correlationRules/relate-queue-to-producer-worker.json +++ b/plugins/Cloudflare/v2/correlationRules/relate-queue-to-producer-worker.json @@ -1,5 +1,5 @@ { - "displayName": "Queue produced to by Worker", + "displayName": "Queue receives messages from Worker", "source": { "types": "Cloudflare Queue" }, @@ -11,10 +11,15 @@ "sourceProperty": "primaryProducerScript", "operator": "equals", "targetProperty": "name" + }, + { + "sourceProperty": "accountId", + "operator": "equals", + "targetProperty": "accountId" } ], "labels": { - "forward": "produced to by", - "reverse": "produces to" + "forward": "receives messages from", + "reverse": "sends messages to" } } diff --git a/plugins/Cloudflare/v2/correlationRules/relate-queue-to-worker.json b/plugins/Cloudflare/v2/correlationRules/relate-queue-to-worker.json index 0783bde9..69913763 100644 --- a/plugins/Cloudflare/v2/correlationRules/relate-queue-to-worker.json +++ b/plugins/Cloudflare/v2/correlationRules/relate-queue-to-worker.json @@ -11,6 +11,11 @@ "sourceProperty": "primaryConsumerScript", "operator": "equals", "targetProperty": "name" + }, + { + "sourceProperty": "accountId", + "operator": "equals", + "targetProperty": "accountId" } ], "labels": { diff --git a/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-queue.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-queue.json index ee11c30a..eb6fc7e5 100644 --- a/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-queue.json +++ b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-queue.json @@ -11,6 +11,11 @@ "sourceProperty": "queueName", "operator": "equals", "targetProperty": "name" + }, + { + "sourceProperty": "accountId", + "operator": "equals", + "targetProperty": "accountId" } ], "labels": { diff --git a/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-r2-bucket.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-r2-bucket.json index 78bd986a..11cbcdce 100644 --- a/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-r2-bucket.json +++ b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-r2-bucket.json @@ -11,6 +11,11 @@ "sourceProperty": "r2BucketName", "operator": "equals", "targetProperty": "name" + }, + { + "sourceProperty": "accountId", + "operator": "equals", + "targetProperty": "accountId" } ], "labels": { diff --git a/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-service-worker.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-service-worker.json index 8a172a72..755b56e9 100644 --- a/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-service-worker.json +++ b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-service-worker.json @@ -11,6 +11,11 @@ "sourceProperty": "serviceName", "operator": "equals", "targetProperty": "name" + }, + { + "sourceProperty": "accountId", + "operator": "equals", + "targetProperty": "accountId" } ], "labels": { diff --git a/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-vectorize-index.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-vectorize-index.json index 51a7fdd9..3c285d58 100644 --- a/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-vectorize-index.json +++ b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-vectorize-index.json @@ -11,6 +11,11 @@ "sourceProperty": "vectorizeIndexName", "operator": "equals", "targetProperty": "name" + }, + { + "sourceProperty": "accountId", + "operator": "equals", + "targetProperty": "accountId" } ], "labels": { diff --git a/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-worker.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-worker.json index 36224232..d305df2a 100644 --- a/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-worker.json +++ b/plugins/Cloudflare/v2/correlationRules/relate-worker-binding-to-worker.json @@ -11,6 +11,11 @@ "sourceProperty": "scriptName", "operator": "equals", "targetProperty": "name" + }, + { + "sourceProperty": "accountId", + "operator": "equals", + "targetProperty": "accountId" } ], "labels": { diff --git a/plugins/Cloudflare/v2/correlationRules/relate-worker-route-to-worker.json b/plugins/Cloudflare/v2/correlationRules/relate-worker-route-to-worker.json index ec69301b..00a77911 100644 --- a/plugins/Cloudflare/v2/correlationRules/relate-worker-route-to-worker.json +++ b/plugins/Cloudflare/v2/correlationRules/relate-worker-route-to-worker.json @@ -11,6 +11,11 @@ "sourceProperty": "scriptName", "operator": "equals", "targetProperty": "name" + }, + { + "sourceProperty": "accountId", + "operator": "equals", + "targetProperty": "accountId" } ], "labels": { diff --git a/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json b/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json index 226dac19..a498d83b 100644 --- a/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json +++ b/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json @@ -42,7 +42,7 @@ "name": "largestContentfulPaintP75", "displayName": "Largest Contentful Paint (P75)", "computed": true, - "valueExpression": "{{ Number($['quantiles.largestContentfulPaintP75']) < 0 ? null : Math.round(Number($['quantiles.largestContentfulPaintP75']) / 1000) }}", + "valueExpression": "{{ Number($['quantiles.largestContentfulPaintP75']) < 0 ? null : Number($['quantiles.largestContentfulPaintP75']) }}", "shape": "milliseconds", "role": "value" }, @@ -58,7 +58,7 @@ "name": "interactionToNextPaintP75", "displayName": "Interaction to Next Paint (P75)", "computed": true, - "valueExpression": "{{ Number($['quantiles.interactionToNextPaintP75']) >= 0 ? Math.round(Number($['quantiles.interactionToNextPaintP75']) / 1000) : (Number($['quantiles.firstInputDelayP75']) >= 0 ? Math.round(Number($['quantiles.firstInputDelayP75']) / 1000) : null) }}", + "valueExpression": "{{ Number($['quantiles.interactionToNextPaintP75']) >= 0 ? Number($['quantiles.interactionToNextPaintP75']) : (Number($['quantiles.firstInputDelayP75']) >= 0 ? Number($['quantiles.firstInputDelayP75']) : null) }}", "shape": "milliseconds" }, { diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/dnsFirewallAnalytics.js b/plugins/Cloudflare/v2/dataStreams/scripts/dnsFirewallAnalytics.js index c4421ca3..cd1ea7e5 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/dnsFirewallAnalytics.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/dnsFirewallAnalytics.js @@ -1,10 +1,3 @@ -// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a -// postRequestScript bypasses the stream's declarative errorHandling entirely, -// so the error is raised here or it would be swallowed into an empty result. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - // dataStreams/scripts/dnsFirewallAnalytics.js // The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the // key holding the dimension value inside each row's `dimensions` object varies with the diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/loadBalancerPoolHealth.js b/plugins/Cloudflare/v2/dataStreams/scripts/loadBalancerPoolHealth.js index 63390fa5..cb35ec8d 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/loadBalancerPoolHealth.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/loadBalancerPoolHealth.js @@ -12,14 +12,17 @@ for (const colo of Object.keys(popHealth)) { rows.push({ colo: colo, origin: originName, - healthy: Boolean(o.healthy), + // Absent health is unknown, not unhealthy - Boolean() would + // report an origin Cloudflare has no data for as down. + healthy: typeof o.healthy === "boolean" ? o.healthy : null, responseCode: typeof o.response_code === "number" ? o.response_code : null, rtt: o.rtt || "", failureReason: o.failure_reason || "", - coloHealthy: Boolean(pop.healthy), + coloHealthy: + typeof pop.healthy === "boolean" ? pop.healthy : null, }); } } diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/pagesProjects.js b/plugins/Cloudflare/v2/dataStreams/scripts/pagesProjects.js index dda18f35..9ebfd45b 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/pagesProjects.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/pagesProjects.js @@ -11,9 +11,9 @@ result = ((data && data.result) || []).map((project) => { projectName: project.name, accountId: accountId, subdomain: project.subdomain || "", - // Kept as an array, not a joined string: it is the join key for the - // Pages Project -> Zone correlation rule, and correlation matches an - // array property if any element matches. + // A readable list for display only. Array properties are JSON-stringified + // on import (SAAS-9816), so the Pages Project -> Zone rule correlates on + // primaryDomain below rather than on this column. domains: (project.domains || []).join(", "), primaryDomain: (project.domains || [])[0] || "", productionBranch: project.production_branch || "", diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/queues.js b/plugins/Cloudflare/v2/dataStreams/scripts/queues.js index a14493e3..dc048a08 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/queues.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/queues.js @@ -16,9 +16,10 @@ result = ((data && data.result) || []).map((queue) => ({ typeof queue.consumers_total_count === "number" ? queue.consumers_total_count : (queue.consumers || []).length, - // The consuming Worker script names, kept as an array: this is the join - // key for the Queue -> Worker correlation rule. HTTP-pull consumers have - // no service name and are filtered out. + // The consuming Worker script names as a readable list, for display only. + // Array properties are JSON-stringified on import (SAAS-9816), so the + // Queue -> Worker rule correlates on primaryConsumerScript below. + // HTTP-pull consumers have no service name and are filtered out. consumerScripts: (queue.consumers || []) .map((c) => c && c.service) .filter(Boolean) @@ -26,7 +27,8 @@ result = ((data && data.result) || []).map((queue) => ({ primaryConsumerScript: ((queue.consumers || []).map((c) => c && c.service).filter(Boolean))[0] || "", - // The producing Worker script names, same join-key reasoning as consumers. + // The producing Worker script names, same display-only reasoning as consumers; + // the producer rule correlates on primaryProducerScript. producerScripts: (queue.producers || []) .map((p) => p && p.script) .filter(Boolean) diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/streamVideos.js b/plugins/Cloudflare/v2/dataStreams/scripts/streamVideos.js index 8b8b2d49..4011627e 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/streamVideos.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/streamVideos.js @@ -12,7 +12,10 @@ result = ((data && data.result) || []).map((v) => { videoName: meta.name || v.uid, accountId: accountId, statusState: status.state || "", - duration: typeof v.duration === "number" ? v.duration : null, + // Cloudflare reports -1 while a video is still being processed and its + // duration is not yet known; that is absent data, not a real length. + duration: + typeof v.duration === "number" && v.duration >= 0 ? v.duration : null, size: typeof v.size === "number" ? v.size : null, readyToStream: Boolean(v.readyToStream), createdOn: v.created, diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/workerRoutes.js b/plugins/Cloudflare/v2/dataStreams/scripts/workerRoutes.js index ead189e9..adf36671 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/workerRoutes.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/workerRoutes.js @@ -6,6 +6,10 @@ const zone = (context.objects && context.objects[0]) || {}; const zoneId = zone.rawId || ""; const zoneName = zone.name || ""; +// Graph properties can arrive as single-element arrays, so unwrap before use. +// accountId scopes the Worker Route -> Worker correlation to one account: two +// accounts can each hold a Worker with the same name. +const accountId = [].concat(zone.accountId || "")[0] || ""; result = ((data && data.result) || []) .filter((route) => route && route.script) @@ -14,5 +18,6 @@ result = ((data && data.result) || []) pattern: route.pattern, zoneId: zoneId, zoneName: zoneName, + accountId: accountId, scriptName: route.script, })); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/zoneNelReports.js b/plugins/Cloudflare/v2/dataStreams/scripts/zoneNelReports.js index f1a142ac..5a654d74 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/zoneNelReports.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/zoneNelReports.js @@ -1,10 +1,3 @@ -// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a -// postRequestScript bypasses the stream's declarative errorHandling entirely, -// so the error is raised here or it would be swallowed into an empty result. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - // dataStreams/scripts/zoneNelReports.js // The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the // key holding the dimension value inside each row's `dimensions` object varies with the diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/zonePageShield.js b/plugins/Cloudflare/v2/dataStreams/scripts/zonePageShield.js index 7862babf..ac6a3b4d 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/zonePageShield.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/zonePageShield.js @@ -1,10 +1,3 @@ -// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a -// postRequestScript bypasses the stream's declarative errorHandling entirely, -// so the error is raised here or it would be swallowed into an empty result. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - // dataStreams/scripts/zonePageShield.js // The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the // key holding the dimension value inside each row's `dimensions` object varies with the diff --git a/plugins/Cloudflare/v2/dataStreams/workerRoutes.json b/plugins/Cloudflare/v2/dataStreams/workerRoutes.json index f6fb05d7..8902f609 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerRoutes.json +++ b/plugins/Cloudflare/v2/dataStreams/workerRoutes.json @@ -34,6 +34,7 @@ "sourceId": "sourceId", "sourceType": "Cloudflare Worker Route" }, + { "name": "accountId", "displayName": "Account ID", "shape": "string" }, { "name": "zoneId", "displayName": "Zone ID", "shape": "string" }, { "name": "zoneName", "displayName": "Zone", "shape": "string" }, { diff --git a/plugins/Cloudflare/v2/defaultContent/AI/aiGateway.dash.json b/plugins/Cloudflare/v2/defaultContent/AI/aiGateway.dash.json index 47e6b31c..c7c6ced7 100644 --- a/plugins/Cloudflare/v2/defaultContent/AI/aiGateway.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/AI/aiGateway.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Requests", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -76,7 +76,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Total Tokens", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -131,7 +131,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Cost", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -186,7 +186,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Errors", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/AI/autorag.dash.json b/plugins/Cloudflare/v2/defaultContent/AI/autorag.dash.json index bbc234a3..b0f32b57 100644 --- a/plugins/Cloudflare/v2/defaultContent/AI/autorag.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/AI/autorag.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Search Events", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -76,7 +76,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "AI Searches", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -131,7 +131,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Searches", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -186,7 +186,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Embedding Models", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/AI/vectorizeIndex.dash.json b/plugins/Cloudflare/v2/defaultContent/AI/vectorizeIndex.dash.json index 61524abe..61a33755 100644 --- a/plugins/Cloudflare/v2/defaultContent/AI/vectorizeIndex.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/AI/vectorizeIndex.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Queries", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -73,7 +73,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Avg Query Latency", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -125,7 +125,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Stored Vectors", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -177,7 +177,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Vector Dimensions", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Compute/containerApplication.dash.json b/plugins/Cloudflare/v2/defaultContent/Compute/containerApplication.dash.json index 730ef301..77e29bf2 100644 --- a/plugins/Cloudflare/v2/defaultContent/Compute/containerApplication.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Compute/containerApplication.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Avg CPU Utilization", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -76,7 +76,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Avg Memory Usage", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -131,7 +131,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Bytes Received", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -186,7 +186,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Bytes Transmitted", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Compute/durableObjectNamespace.dash.json b/plugins/Cloudflare/v2/defaultContent/Compute/durableObjectNamespace.dash.json index 97df92e0..cb0ee505 100644 --- a/plugins/Cloudflare/v2/defaultContent/Compute/durableObjectNamespace.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Compute/durableObjectNamespace.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Requests", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -73,7 +73,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Errors", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -125,7 +125,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Wall Time P99", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -177,7 +177,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Storage Size", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Compute/pipeline.dash.json b/plugins/Cloudflare/v2/defaultContent/Compute/pipeline.dash.json index 311c1a86..70980886 100644 --- a/plugins/Cloudflare/v2/defaultContent/Compute/pipeline.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Compute/pipeline.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Records Ingested", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -73,7 +73,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Bytes Ingested", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -125,7 +125,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Ingestion Operations", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -177,7 +177,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Peak Daily Records", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Compute/queue.dash.json b/plugins/Cloudflare/v2/defaultContent/Compute/queue.dash.json index a0c9d5b4..25bc734b 100644 --- a/plugins/Cloudflare/v2/defaultContent/Compute/queue.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Compute/queue.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Message Operations", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -73,7 +73,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Billable Operations", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -125,7 +125,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Bytes Processed", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -177,7 +177,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Average Backlog", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Compute/worker.dash.json b/plugins/Cloudflare/v2/defaultContent/Compute/worker.dash.json index 1cb6ec5c..64abe644 100644 --- a/plugins/Cloudflare/v2/defaultContent/Compute/worker.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Compute/worker.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Requests", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -73,7 +73,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Errors", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -125,7 +125,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Subrequests", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -177,7 +177,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Peak CPU Time P99", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Core/account.dash.json b/plugins/Cloudflare/v2/defaultContent/Core/account.dash.json index 4de065a7..4dd20781 100644 --- a/plugins/Cloudflare/v2/defaultContent/Core/account.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Core/account.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Workers", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -71,7 +71,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Pages Projects", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -121,7 +121,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Tunnels", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -171,7 +171,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "R2 Buckets", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -973,7 +973,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Gateway DNS Queries", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -1029,7 +1029,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Gateway HTTP Requests", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -1085,7 +1085,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "AI Inference Requests", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -1141,7 +1141,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "AI Output Tokens", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -1517,7 +1517,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Gateway Network Sessions", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -1965,7 +1965,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Audit Log Actions", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -2021,7 +2021,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Image Requests", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -2074,7 +2074,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Image Transformations", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -2127,7 +2127,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Pages Function Requests", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json b/plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json index 208ccc8a..abc908d6 100644 --- a/plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Requests", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -73,7 +73,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Unique Visitors", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -125,7 +125,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Bandwidth", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -177,7 +177,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Threats", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -1349,7 +1349,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "LCP (P75)", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -1402,7 +1402,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "INP (P75)", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -1455,7 +1455,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "CLS (P75)", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -1508,7 +1508,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "RUM Samples", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Media/realtimeApp.dash.json b/plugins/Cloudflare/v2/defaultContent/Media/realtimeApp.dash.json index 76523d73..ad05b110 100644 --- a/plugins/Cloudflare/v2/defaultContent/Media/realtimeApp.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Media/realtimeApp.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Bytes Sent", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -73,7 +73,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Bytes Received", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -125,7 +125,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Track Types", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -177,7 +177,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Peak Track Daily Sent", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -212,7 +212,7 @@ "data-stream-scalar": { "value": "sum.egressBytes_max", "comparisonColumn": "none", - "label": "Peak Daily Sent" + "label": "Peak Track Daily Sent" } } } diff --git a/plugins/Cloudflare/v2/defaultContent/Media/streamVideo.dash.json b/plugins/Cloudflare/v2/defaultContent/Media/streamVideo.dash.json index 5862b162..78e813ec 100644 --- a/plugins/Cloudflare/v2/defaultContent/Media/streamVideo.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Media/streamVideo.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Minutes Viewed", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -73,7 +73,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Playback Samples", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -128,7 +128,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Avg Buffering", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -183,7 +183,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Avg Startup Buffering", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Storage & Databases/d1Database.dash.json b/plugins/Cloudflare/v2/defaultContent/Storage & Databases/d1Database.dash.json index 62f6be5d..e3b6edf6 100644 --- a/plugins/Cloudflare/v2/defaultContent/Storage & Databases/d1Database.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Storage & Databases/d1Database.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Read Queries", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -73,7 +73,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Write Queries", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -125,7 +125,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Rows Read", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -177,7 +177,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Database Size", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Storage & Databases/hyperdriveConfig.dash.json b/plugins/Cloudflare/v2/defaultContent/Storage & Databases/hyperdriveConfig.dash.json index 4c55ff62..d2c1ee83 100644 --- a/plugins/Cloudflare/v2/defaultContent/Storage & Databases/hyperdriveConfig.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Storage & Databases/hyperdriveConfig.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Queries", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -73,7 +73,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Avg Query Latency", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -125,7 +125,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Peak Daily Queries", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -177,7 +177,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Peak Query Latency", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Storage & Databases/kvNamespace.dash.json b/plugins/Cloudflare/v2/defaultContent/Storage & Databases/kvNamespace.dash.json index 64d9f234..6df7961b 100644 --- a/plugins/Cloudflare/v2/defaultContent/Storage & Databases/kvNamespace.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Storage & Databases/kvNamespace.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Requests", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -73,7 +73,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Keys", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -125,7 +125,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Stored Bytes", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -177,7 +177,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Peak Latency P99", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Storage & Databases/r2Bucket.dash.json b/plugins/Cloudflare/v2/defaultContent/Storage & Databases/r2Bucket.dash.json index 4aa715a4..d841eb4e 100644 --- a/plugins/Cloudflare/v2/defaultContent/Storage & Databases/r2Bucket.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Storage & Databases/r2Bucket.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Requests", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -73,7 +73,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Data Transferred", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -125,7 +125,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Objects", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -177,7 +177,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Stored Bytes", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Traffic/loadBalancerPool.dash.json b/plugins/Cloudflare/v2/defaultContent/Traffic/loadBalancerPool.dash.json index 2c83d63f..fee2e185 100644 --- a/plugins/Cloudflare/v2/defaultContent/Traffic/loadBalancerPool.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Traffic/loadBalancerPool.dash.json @@ -69,7 +69,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Origin Checks", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -119,7 +119,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Unhealthy Checks", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Zero Trust/accessApplication.dash.json b/plugins/Cloudflare/v2/defaultContent/Zero Trust/accessApplication.dash.json index 6f1bd8d5..610e6381 100644 --- a/plugins/Cloudflare/v2/defaultContent/Zero Trust/accessApplication.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Zero Trust/accessApplication.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Logins", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -74,7 +74,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Successful Logins", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -137,7 +137,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Failed Logins", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -200,7 +200,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Countries", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Zero Trust/tunnel.dash.json b/plugins/Cloudflare/v2/defaultContent/Zero Trust/tunnel.dash.json index ca7a93fd..c0ce8dfa 100644 --- a/plugins/Cloudflare/v2/defaultContent/Zero Trust/tunnel.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Zero Trust/tunnel.dash.json @@ -69,7 +69,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Connections", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -119,7 +119,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Data Centres", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Zero Trust/turnstileWidget.dash.json b/plugins/Cloudflare/v2/defaultContent/Zero Trust/turnstileWidget.dash.json index 468f9d3a..2f4dcf6a 100644 --- a/plugins/Cloudflare/v2/defaultContent/Zero Trust/turnstileWidget.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Zero Trust/turnstileWidget.dash.json @@ -21,7 +21,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Challenges", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -76,7 +76,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Peak Challenges", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -131,7 +131,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Event Types", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -186,7 +186,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Actions", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/overview.dash.json b/plugins/Cloudflare/v2/defaultContent/overview.dash.json index 8b5577a1..ffc80611 100644 --- a/plugins/Cloudflare/v2/defaultContent/overview.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/overview.dash.json @@ -19,7 +19,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Accounts", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -58,7 +58,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Zones", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -97,7 +97,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Workers", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -136,7 +136,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Pages Projects", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -175,7 +175,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "R2 Buckets", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -214,7 +214,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "KV Namespaces", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -253,7 +253,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "D1 Databases", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -292,7 +292,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Queues", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -331,7 +331,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Tunnels", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -370,7 +370,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Load Balancer Pools", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -409,7 +409,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Access Applications", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -448,7 +448,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Zones Paused", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -497,7 +497,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Durable Object Namespaces", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -536,7 +536,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Vectorize Indexes", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -575,7 +575,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Hyperdrive Configs", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -614,7 +614,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Worker Routes", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -653,7 +653,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "", + "title": "Worker Bindings", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/docs/README.md b/plugins/Cloudflare/v2/docs/README.md index 3159e07c..a1f73107 100644 --- a/plugins/Cloudflare/v2/docs/README.md +++ b/plugins/Cloudflare/v2/docs/README.md @@ -1,6 +1,6 @@ Monitor your [Cloudflare](https://www.cloudflare.com) account in SquaredUp - zone traffic and cache performance, firewall and WAF activity, DNS records and SSL certificate expiry, plus the developer platform: Workers, R2, KV, D1, Queues, Pages, Tunnels, Load Balancers and Access applications. Data comes from the [Cloudflare REST API](https://developers.cloudflare.com/api/) and the [GraphQL Analytics API](https://developers.cloudflare.com/analytics/graphql-api/). -> ⚠️ This plugin is **read-only** and never changes anything in your Cloudflare account. It does not cover Logpush, Magic Transit, Magic WAN, Spectrum, Stream, Images, Turnstile or Waiting Room. +> ⚠️ This plugin is **read-only** and never changes anything in your Cloudflare account. It does not cover Logpush, Magic Transit, Magic WAN, Spectrum or Waiting Room. ## Setup @@ -172,21 +172,25 @@ Cloudflare's GraphQL Analytics API exposes far more datasets than this plugin sh | ------------ | -------------- | | Every resource **belongs to** its Account | the resource's `accountId` against the account's id | | Worker Binding **declared by** Worker, and **targets** the KV namespace / R2 bucket / D1 database / queue / Durable Object namespace / Vectorize index / Hyperdrive config it points at | the binding's target id against that resource's id | -| Worker Binding **calls** Worker | a service binding's target script name against the Worker name | +| Worker Binding **calls** Worker | a service binding's target script name against the Worker name, within the same account | | Worker **serves** Zone | through the Worker Route that names both | | Worker Route **routes to** Worker, and **belongs to** Zone | the route's script name and zone id | -| Durable Object Namespace **implemented by** Worker | the namespace's script name against the Worker name | +| Durable Object Namespace **implemented by** Worker | the namespace's script name against the Worker name, within the same account | | Pages Project **served by** Zone | the project's first custom domain against the zone name | -| Queue **consumed by** Worker, and **produced to by** Worker | the queue's first consumer and first producer script name against the Worker name | +| Queue **consumed by** Worker, and **receives messages from** Worker | the queue's first consumer and first producer script name against the Worker name, within the same account | | Turnstile Widget **protects** Zone | the widget's first allowed domain against the zone name | | Access Application **protects** Zone | the registrable domain derived from the app's hostname against the zone name | Together these give a dependency graph: from a KV namespace you can see which Workers bind it, and from a Worker which zones it serves. +Rules that match on a name rather than an id also match on `accountId`. Cloudflare only guarantees a Worker, queue, bucket or index name is unique within an account, so a token that can read two accounts would otherwise draw edges between resources in one and a same-named Worker in the other. + Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed with the account id (`:`) because Cloudflare only guarantees those names are unique within an account. Every other type uses its own Cloudflare id. ## Known limitations +- **Access Applications only correlate to zones under a single-label suffix.** The rule derives the zone from the application's hostname by taking its last two labels, so `login.example.com` matches the zone `example.com`. Under a multi-label public suffix that is wrong - `login.example.co.uk` reduces to `co.uk`, which matches no zone, so the edge is not drawn. Correlation expressions have no public-suffix list to consult and Cloudflare does not return a zone id on the Access application, so applications on `.co.uk`, `.com.au` and similar domains are left unrelated rather than related to the wrong zone. + - **One-to-many relationships only correlate on their first value.** The import serialises an array-valued property to a JSON string (`["a.com","b.com"]`) rather than storing it as a multi-valued property, and correlation conditions only offer `equals`, so an array can never match a scalar. Where a Cloudflare object names several others - a Turnstile widget's allowed domains, a Pages project's custom domains, a queue's consumers and producers - the plugin stores the full list as a readable string for display and a separate `primary*` property holding the first entry, and correlates on that. A widget covering three zones therefore draws an edge to one of them. The same constraint is why Kubernetes, the only other plugin here shipping correlation rules, joins on `primaryBackendServiceName` rather than the full backend list. - **Analytics timeframes are capped per dataset, and the caps are short.** Cloudflare's GraphQL Analytics API limits how wide a single query's time range can be, and the limit differs for every dataset. These were measured against a Pro-plan account: @@ -215,6 +219,8 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w - **Pages endpoints cap page size at 10.** Cloudflare rejects any larger `per_page` on the Pages API, so Pages projects and deployments are fetched ten at a time. - **Some resource lists are not paged.** R2 buckets, D1 databases, Queues, load balancer pools, Access applications, Vectorize indexes, Hyperdrive configs, Worker scripts and Worker routes are imported in a single request each. Where Cloudflare's paging behaviour could be proven against real data it is used (zones, accounts, DNS records, Pages projects, KV namespaces, Tunnels and Durable Object namespaces all page); the rest were left unpaged because the endpoint either ignores the paging parameters outright — as `workers/scripts` does — or holds too few records in the tested account to confirm they are honoured. If an account holds more of one of these than Cloudflare returns on a single page, the remainder is not imported. - **Rate limits.** The REST API allowed 1,200 requests per 300 seconds on the token tested, and Cloudflare documents a separate limit of 300 GraphQL queries per 5 minutes. Every analytics stream issues one request per selected object, so very large estates can hit these limits. +- **Long timeframes on per-minute analytics can return a partial series.** Cloudflare caps a GraphQL result at 10,000 rows, and the streams that break down by `datetime` produce one row per minute per dimension value - Worker Invocations, Pages Functions Invocations, Durable Object Invocations and Subrequests, D1 Queries, Queue Backlog and Consumer Metrics, R2 Operations and Storage, Cache Reserve Storage, Gateway HTTP Requests, Container Metrics, Pipeline Ingestion, Browser Rendering, Realtime Usage and Audit Logs. A busy resource can exceed 10,000 rows well inside `last30days`; because the queries order by time ascending, the excess is dropped from the end and the tile shows the earliest part of the range as though the series simply stopped. Prefer a narrower timeframe when a chart appears to end early. + - **Hand-written GraphQL queries are unbounded.** The **GraphQL Query** stream runs whatever you give it, so it can hit limits the built-in streams are tuned to avoid: a large `limit` on a multi-dimension dataset can exceed the ~6 MB response cap, and a timeframe wider than that dataset's own cap fails outright. Prefer the pre-aggregated `*Groups` datasets over raw event datasets, and keep `limit` modest. The stream does not page, so your `limit` is the ceiling. - **Some analytics are only available on paid plans.** Page Shield and Network Error Logs return an authorization error on plans without them; Cache Reserve, Load Balancing and Health Checks are add-ons. An unentitled feature shows no data rather than an error in most tiles. - **A failed Cloudflare query can look like "no data".** Cloudflare answers a failed GraphQL query with HTTP 200 and an `errors` array, which the platform does not treat as a failure. Streams that use a post-request script raise these errors explicitly, but the simpler declarative streams will show an empty tile instead of an error message. diff --git a/plugins/Cloudflare/v2/indexDefinitions/default.json b/plugins/Cloudflare/v2/indexDefinitions/default.json index c0135ff8..ffe5b6c0 100644 --- a/plugins/Cloudflare/v2/indexDefinitions/default.json +++ b/plugins/Cloudflare/v2/indexDefinitions/default.json @@ -34,6 +34,7 @@ "name": "zones" }, "timeframe": "none", + "optional": true, "objectMapping": { "id": "id", "name": "name", @@ -424,6 +425,7 @@ "value": "Cloudflare Worker Route" }, "properties": [ + "accountId", "zoneId", "zoneName", "scriptName" diff --git a/plugins/Cloudflare/v2/metadata.json b/plugins/Cloudflare/v2/metadata.json index c93c4954..eb6afe1a 100644 --- a/plugins/Cloudflare/v2/metadata.json +++ b/plugins/Cloudflare/v2/metadata.json @@ -7,7 +7,7 @@ "type": "community" }, "description": "Monitor your Cloudflare account in SquaredUp - zone traffic, cache performance, firewall and WAF events, DNS records and SSL certificate expiry, plus Workers, R2, KV, D1, Queues, Pages, Tunnels, Load Balancers and Access applications.", - "category": "CDN", + "category": "Cloud Platforms", "type": "hybrid", "schemaVersion": "2.1", "importNotSupported": false, From 15977887b1aa9383807a9655a9df8ac57be714bf Mon Sep 17 00:00:00 2001 From: Andrew Harris Date: Wed, 9 Sep 2026 16:14:02 +0100 Subject: [PATCH 13/27] Stamp zoneTraffic response with the scoped objects zoneName and zoneTag --- .../v2/dataStreams/scripts/zoneTraffic.js | 44 +++++++++++++++++++ .../v2/dataStreams/zoneTraffic.json | 18 +++++++- 2 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/zoneTraffic.js diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/zoneTraffic.js b/plugins/Cloudflare/v2/dataStreams/scripts/zoneTraffic.js new file mode 100644 index 00000000..dbc7ef2b --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/scripts/zoneTraffic.js @@ -0,0 +1,44 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + +// dataStreams/scripts/zoneTraffic.js +// SquaredUp runs this stream once per zone in scope and joins the rows, so a tile +// scoped to several zones cannot tell which rows belong to which zone. Stamp the +// scoped zone's tag and name onto every row so tiles and SQL can group by zone. +// Column names keep the dotted form the previous expandInnerObjects config produced. + +const zone = (context.objects && context.objects[0]) || {}; +const zoneTag = zone.rawId || ""; +const zoneName = zone.name || zoneTag; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.zones && + data.data.viewer.zones[0] && + data.data.viewer.zones[0].httpRequests1hGroups) || + []; + +result = groups.map((row) => { + const sum = row.sum || {}; + const uniq = row.uniq || {}; + + return { + zoneTag: zoneTag, + zoneName: zoneName, + "dimensions.datetime": row.dimensions && row.dimensions.datetime, + "sum.requests": Number(sum.requests || 0) || 0, + "sum.cachedRequests": Number(sum.cachedRequests || 0) || 0, + "sum.bytes": Number(sum.bytes || 0) || 0, + "sum.cachedBytes": Number(sum.cachedBytes || 0) || 0, + "sum.threats": Number(sum.threats || 0) || 0, + "sum.pageViews": Number(sum.pageViews || 0) || 0, + "sum.encryptedRequests": Number(sum.encryptedRequests || 0) || 0, + "uniq.uniques": Number(uniq.uniques || 0) || 0 + }; +}); diff --git a/plugins/Cloudflare/v2/dataStreams/zoneTraffic.json b/plugins/Cloudflare/v2/dataStreams/zoneTraffic.json index 79c35676..04e979fb 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneTraffic.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneTraffic.json @@ -18,8 +18,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.zones.0.httpRequests1hGroups", - "expandInnerObjects": true, + "postRequestScript": "zoneTraffic.js", "errorHandling": { "type": "path", "realm": "payload", @@ -35,6 +34,21 @@ } }, "metadata": [ + { + "name": "zoneTag", + "displayName": "Zone Tag", + "shape": "string", + "role": "id", + "visible": false + }, + { + "name": "zoneName", + "displayName": "Zone", + "shape": "string", + "role": "label", + "sourceId": "zoneTag", + "sourceType": "Cloudflare Zone" + }, { "name": "dimensions.datetime", "displayName": "Time", From bb09fad29bf964f197f7d7f50d7471f89ef56fc4 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Nov 2026 20:34:43 +0000 Subject: [PATCH 14/27] Widen Cloudflare analytics timeframes to each dataset's real limits Timeframe lists were set from caps measured by trial and error, several of which were wrong (DNS Analytics and Zone Traffic Breakdown allow 30-31 days, not ~7-8). They now follow the limits Cloudflare reports through its GraphQL settings API for each dataset, confirmed by running every stream at every offered timeframe against a live account. - Switch KV, D1, Access, AI Gateway, AutoRAG, Hyperdrive, Vectorize, Durable Object storage and Stream streams from date to datetime filters, so they offer intraday timeframes. - Choose the time bucket from the timeframe (minute up to daily) and alias it onto the existing column, so names and scripts are unchanged. This also stops per-minute streams truncating long ranges at the 10,000-row cap. - Add This/Last month and quarter where history allows, and serve Zone Traffic from the daily dataset beyond two days so it reaches This year. - Start one minute late on datasets whose cap equals the timeframe width; Cloudflare measures to receipt time, so Last 24 hours on Firewall Events and Last 30 days on Zone Traffic Breakdown were rejected intermittently. - Order breakdown streams by count so truncation drops rare values, not the most recent part of the range. - Offer Last 7 and 30 days on Zone Firewall Events for higher plans, with an error naming the plan's limit where it is shorter. - Allow every timeframe on GraphQL Query and document the limits, including how to read an account's own limits. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01FsDuPXY2CFtKbw4Cxn6cRF --- .../v2/dataStreams/accessLogins.json | 12 ++-- .../v2/dataStreams/aiGatewayCache.json | 10 +-- .../v2/dataStreams/aiGatewayErrors.json | 10 +-- .../v2/dataStreams/aiGatewayRequests.json | 13 ++-- .../Cloudflare/v2/dataStreams/auditLogs.json | 10 ++- .../v2/dataStreams/autoragQueries.json | 10 +-- .../v2/dataStreams/browserRendering.json | 6 +- .../dataStreams/cacheReserveOperations.json | 4 +- .../v2/dataStreams/cacheReserveStorage.json | 4 +- .../v2/dataStreams/containerMetrics.json | 6 +- .../v2/dataStreams/d1Analytics.json | 12 ++-- .../Cloudflare/v2/dataStreams/d1Queries.json | 9 +-- .../Cloudflare/v2/dataStreams/d1Storage.json | 12 ++-- .../v2/dataStreams/dmarcReports.json | 6 +- .../v2/dataStreams/dnsFirewallAnalytics.json | 6 +- .../dataStreams/durableObjectInvocations.json | 4 +- .../v2/dataStreams/durableObjectStorage.json | 12 ++-- .../dataStreams/durableObjectSubrequests.json | 9 +-- .../v2/dataStreams/emailRouting.json | 6 +- .../v2/dataStreams/gatewayDnsQueries.json | 6 +- .../v2/dataStreams/gatewayHttpRequests.json | 8 +-- .../dataStreams/gatewayNetworkSessions.json | 8 +-- .../v2/dataStreams/graphqlQuery.json | 12 +++- .../v2/dataStreams/hyperdriveQueries.json | 12 ++-- .../v2/dataStreams/imagesRequests.json | 8 +-- .../v2/dataStreams/imagesTransformations.json | 2 +- .../v2/dataStreams/kvOperations.json | 12 ++-- .../Cloudflare/v2/dataStreams/kvStorage.json | 12 ++-- .../pagesFunctionsInvocations.json | 4 +- .../v2/dataStreams/pipelineIngestion.json | 6 +- .../v2/dataStreams/queueBacklog.json | 4 +- .../v2/dataStreams/queueConsumerMetrics.json | 9 +-- .../dataStreams/queueMessageOperations.json | 4 +- .../v2/dataStreams/r2Operations.json | 4 +- .../Cloudflare/v2/dataStreams/r2Storage.json | 4 +- .../v2/dataStreams/realtimeUsage.json | 6 +- .../v2/dataStreams/rumPageLoads.json | 15 +++- .../v2/dataStreams/rumWebVitals.json | 17 +++-- .../dataStreams/scripts/zoneFirewallEvents.js | 26 ++++++- .../v2/dataStreams/scripts/zoneTraffic.js | 6 +- .../Cloudflare/v2/dataStreams/streamCmcd.json | 12 ++-- .../v2/dataStreams/streamMinutesViewed.json | 12 ++-- .../v2/dataStreams/turnstileChallenges.json | 4 +- .../v2/dataStreams/vectorizeQueries.json | 12 ++-- .../v2/dataStreams/vectorizeStorage.json | 12 ++-- .../v2/dataStreams/workerInvocations.json | 9 +-- .../v2/dataStreams/workersAiInference.json | 6 +- .../v2/dataStreams/zoneDnsAnalytics.json | 8 +-- .../v2/dataStreams/zoneFirewallEvents.json | 4 +- .../v2/dataStreams/zoneHealthCheckEvents.json | 4 +- .../v2/dataStreams/zoneLoadBalancing.json | 4 +- .../v2/dataStreams/zoneNelReports.json | 8 +-- .../v2/dataStreams/zonePageShield.json | 8 +-- .../v2/dataStreams/zoneTraffic.json | 17 +++-- .../v2/dataStreams/zoneTrafficBreakdown.json | 4 +- plugins/Cloudflare/v2/docs/README.md | 69 ++++++++++++------- 56 files changed, 299 insertions(+), 240 deletions(-) diff --git a/plugins/Cloudflare/v2/dataStreams/accessLogins.json b/plugins/Cloudflare/v2/dataStreams/accessLogins.json index 4d192d74..4cf1c6c9 100644 --- a/plugins/Cloudflare/v2/dataStreams/accessLogins.json +++ b/plugins/Cloudflare/v2/dataStreams/accessLogins.json @@ -1,19 +1,19 @@ { "name": "accessLogins", "displayName": "Access Logins", - "description": "Daily Zero Trust login attempts for an Access application by identity provider, country and outcome", + "description": "Zero Trust login attempts for an Access application by identity provider, country and outcome", "tags": ["Security", "Analytics"], "baseDataSourceName": "httpRequestScopedSingle", "config": { "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$appId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){accessLoginRequestsAdaptiveGroups(limit:10000,filter:{appId:$appId,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){count dimensions{date identityProvider isSuccessfulLogin country hasWarpEnabled}}}}}", + "query": "query($accountTag:string!,$appId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){accessLoginRequestsAdaptiveGroups(limit:10000,filter:{appId:$appId,datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} identityProvider isSuccessfulLogin country hasWarpEnabled}}}}}", "variables": { "accountTag": "{{object.accountId}}", "appId": "{{object.rawId}}", - "start": "{{timeframe.start.split('T')[0]}}", - "end": "{{timeframe.end.split('T')[0]}}" + "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", + "end": "{{timeframe.end}}" } }, "pathToData": "data.viewer.accounts.0.accessLoginRequestsAdaptiveGroups", @@ -34,7 +34,7 @@ "metadata": [ { "name": "dimensions.date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -66,5 +66,5 @@ "role": "value" } ], - "timeframes": ["last7days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days"] } diff --git a/plugins/Cloudflare/v2/dataStreams/aiGatewayCache.json b/plugins/Cloudflare/v2/dataStreams/aiGatewayCache.json index 75f5d853..64d0c37a 100644 --- a/plugins/Cloudflare/v2/dataStreams/aiGatewayCache.json +++ b/plugins/Cloudflare/v2/dataStreams/aiGatewayCache.json @@ -8,12 +8,12 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$gateway:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){aiGatewayCacheAdaptiveGroups(limit:10000,filter:{gateway:$gateway,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){count dimensions{date cacheOp}}}}}", + "query": "query($accountTag:string!,$gateway:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiGatewayCacheAdaptiveGroups(limit:10000,filter:{gateway:$gateway,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} cacheOp}}}}}", "variables": { "accountTag": "{{object.accountId}}", "gateway": "{{object.name}}", - "start": "{{timeframe.start.split('T')[0]}}", - "end": "{{timeframe.end.split('T')[0]}}" + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" } }, "pathToData": "data.viewer.accounts.0.aiGatewayCacheAdaptiveGroups", @@ -34,7 +34,7 @@ "metadata": [ { "name": "dimensions.date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -53,5 +53,5 @@ "role": "value" } ], - "timeframes": ["last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/aiGatewayErrors.json b/plugins/Cloudflare/v2/dataStreams/aiGatewayErrors.json index 4934fa39..8eafa4ed 100644 --- a/plugins/Cloudflare/v2/dataStreams/aiGatewayErrors.json +++ b/plugins/Cloudflare/v2/dataStreams/aiGatewayErrors.json @@ -8,12 +8,12 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$gateway:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){aiGatewayErrorsAdaptiveGroups(limit:10000,filter:{gateway:$gateway,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){count dimensions{date {{breakdown}}}}}}}", + "query": "query($accountTag:string!,$gateway:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiGatewayErrorsAdaptiveGroups(limit:10000,filter:{gateway:$gateway,datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "gateway": "{{object.name}}", - "start": "{{timeframe.start.split('T')[0]}}", - "end": "{{timeframe.end.split('T')[0]}}" + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" } }, "pathToData": "data.viewer.accounts.0.aiGatewayErrorsAdaptiveGroups", @@ -47,7 +47,7 @@ "metadata": [ { "name": "dimensions.date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -67,5 +67,5 @@ "role": "value" } ], - "timeframes": ["last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/aiGatewayRequests.json b/plugins/Cloudflare/v2/dataStreams/aiGatewayRequests.json index 4f03cc84..e07c635a 100644 --- a/plugins/Cloudflare/v2/dataStreams/aiGatewayRequests.json +++ b/plugins/Cloudflare/v2/dataStreams/aiGatewayRequests.json @@ -11,12 +11,12 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$gateway:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){aiGatewayRequestsAdaptiveGroups(limit:10000,filter:{gateway:$gateway,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){count dimensions{date {{breakdown}}} sum{cost tokensIn tokensOut totalTokens cachedRequests erroredRequests} quantiles{durationMsP50 durationMsP95}}}}}", + "query": "query($accountTag:string!,$gateway:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiGatewayRequestsAdaptiveGroups(limit:10000,filter:{gateway:$gateway,datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}} sum{cost tokensIn tokensOut totalTokens cachedRequests erroredRequests} quantiles{durationMsP50 durationMsP95}}}}}", "variables": { "accountTag": "{{object.accountId}}", "gateway": "{{object.name}}", - "start": "{{timeframe.start.split('T')[0]}}", - "end": "{{timeframe.end.split('T')[0]}}" + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" } }, "pathToData": "data.viewer.accounts.0.aiGatewayRequestsAdaptiveGroups", @@ -64,7 +64,7 @@ "metadata": [ { "name": "dimensions.date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -139,8 +139,5 @@ "shape": "milliseconds" } ], - "timeframes": [ - "last7days", - "last30days" - ] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/auditLogs.json b/plugins/Cloudflare/v2/dataStreams/auditLogs.json index ca10571e..d9d297f5 100644 --- a/plugins/Cloudflare/v2/dataStreams/auditLogs.json +++ b/plugins/Cloudflare/v2/dataStreams/auditLogs.json @@ -11,7 +11,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){auditLogsGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count dimensions{date {{breakdown}}}}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){auditLogsGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "accountTag": "{{object.rawId}}", "start": "{{timeframe.start}}", @@ -50,7 +50,7 @@ "metadata": [ { "name": "date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -68,10 +68,14 @@ } ], "timeframes": [ + "last1hour", + "last12hours", "last24hours", "last7days", "last30days", "thisMonth", - "lastMonth" + "lastMonth", + "thisQuarter", + "lastQuarter" ] } diff --git a/plugins/Cloudflare/v2/dataStreams/autoragQueries.json b/plugins/Cloudflare/v2/dataStreams/autoragQueries.json index 64c48693..7a9aa21b 100644 --- a/plugins/Cloudflare/v2/dataStreams/autoragQueries.json +++ b/plugins/Cloudflare/v2/dataStreams/autoragQueries.json @@ -8,12 +8,12 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$instanceId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){aiSearchAPIAdaptiveGroups(limit:10000,filter:{instanceId:$instanceId,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){count sum{aiSearchCount searchCount} dimensions{date {{breakdown}}}}}}}", + "query": "query($accountTag:string!,$instanceId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiSearchAPIAdaptiveGroups(limit:10000,filter:{instanceId:$instanceId,datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count sum{aiSearchCount searchCount} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "instanceId": "{{object.rawId}}", - "start": "{{timeframe.start.split('T')[0]}}", - "end": "{{timeframe.end.split('T')[0]}}" + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" } }, "pathToData": "data.viewer.accounts.0.aiSearchAPIAdaptiveGroups", @@ -48,7 +48,7 @@ "metadata": [ { "name": "dimensions.date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -79,5 +79,5 @@ "shape": "number" } ], - "timeframes": ["last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/browserRendering.json b/plugins/Cloudflare/v2/dataStreams/browserRendering.json index 621faf98..5f27872a 100644 --- a/plugins/Cloudflare/v2/dataStreams/browserRendering.json +++ b/plugins/Cloudflare/v2/dataStreams/browserRendering.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){browserRenderingEventsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count avg{avgConcurrentSessions} min{earliestBrowserStartTime} max{latestBrowserEndTime} dimensions{date sessionId {{breakdown}}}}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){browserRenderingEventsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count avg{avgConcurrentSessions} min{earliestBrowserStartTime} max{latestBrowserEndTime} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} sessionId {{breakdown}}}}}}}", "variables": { "accountTag": "{{object.rawId}}", "start": "{{timeframe.start}}", @@ -45,7 +45,7 @@ "metadata": [ { "name": "date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -89,5 +89,5 @@ "visible": false } ], - "timeframes": ["last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json b/plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json index 0be8f98e..f426006f 100644 --- a/plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json +++ b/plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){cacheReserveOperationsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){sum{requests}dimensions{datetime {{breakdown}}}}}}}", + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){cacheReserveOperationsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){sum{requests}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "zoneTag": "{{object.rawId}}", "start": "{{timeframe.start}}", @@ -58,5 +58,5 @@ "role": "value" } ], - "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/cacheReserveStorage.json b/plugins/Cloudflare/v2/dataStreams/cacheReserveStorage.json index ede3d9d3..106eb3aa 100644 --- a/plugins/Cloudflare/v2/dataStreams/cacheReserveStorage.json +++ b/plugins/Cloudflare/v2/dataStreams/cacheReserveStorage.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){cacheReserveStorageAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){max{objectCount storedBytes}dimensions{datetime}}}}}", + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){cacheReserveStorageAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){max{objectCount storedBytes}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { "zoneTag": "{{object.rawId}}", "start": "{{timeframe.start}}", @@ -46,5 +46,5 @@ "shape": "number" } ], - "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/containerMetrics.json b/plugins/Cloudflare/v2/dataStreams/containerMetrics.json index 1b3e715d..1315eb59 100644 --- a/plugins/Cloudflare/v2/dataStreams/containerMetrics.json +++ b/plugins/Cloudflare/v2/dataStreams/containerMetrics.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$applicationId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){containersMetricsAdaptiveGroups(limit:10000,filter:{applicationId:$applicationId,datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count avg{cpuUtilization memory containerUptime} sum{rxBytes txBytes} dimensions{date {{breakdown}}}}}}}", + "query": "query($accountTag:string!,$applicationId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){containersMetricsAdaptiveGroups(limit:10000,filter:{applicationId:$applicationId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){count avg{cpuUtilization memory containerUptime} sum{rxBytes txBytes} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} {{breakdown}}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "applicationId": "{{object.rawId}}", @@ -47,7 +47,7 @@ "metadata": [ { "name": "date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -89,5 +89,5 @@ "shape": "bytes" } ], - "timeframes": ["last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/d1Analytics.json b/plugins/Cloudflare/v2/dataStreams/d1Analytics.json index 797562ef..622915f0 100644 --- a/plugins/Cloudflare/v2/dataStreams/d1Analytics.json +++ b/plugins/Cloudflare/v2/dataStreams/d1Analytics.json @@ -1,19 +1,19 @@ { "name": "d1Analytics", "displayName": "D1 Queries", - "description": "Daily read and write query counts, rows touched and query latency for a D1 database", + "description": "Read and write query counts, rows touched and query latency for a D1 database", "tags": ["Database", "Analytics"], "baseDataSourceName": "httpRequestScopedSingle", "config": { "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$databaseId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){d1AnalyticsAdaptiveGroups(limit:10000,filter:{databaseId:$databaseId,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){sum{readQueries writeQueries rowsRead rowsWritten queryBatchResponseBytes}quantiles{queryBatchTimeMsP50 queryBatchTimeMsP90 queryBatchTimeMsP99}dimensions{date}}}}}", + "query": "query($accountTag:string!,$databaseId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){d1AnalyticsAdaptiveGroups(limit:10000,filter:{databaseId:$databaseId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{readQueries writeQueries rowsRead rowsWritten queryBatchResponseBytes}quantiles{queryBatchTimeMsP50 queryBatchTimeMsP90 queryBatchTimeMsP99}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "databaseId": "{{object.rawId}}", - "start": "{{timeframe.start.split('T')[0]}}", - "end": "{{timeframe.end.split('T')[0]}}" + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" } }, "pathToData": "data.viewer.accounts.0.d1AnalyticsAdaptiveGroups", @@ -34,7 +34,7 @@ "metadata": [ { "name": "dimensions.date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -80,5 +80,5 @@ "shape": "milliseconds" } ], - "timeframes": ["last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/d1Queries.json b/plugins/Cloudflare/v2/dataStreams/d1Queries.json index b15d5dd8..594ce1ad 100644 --- a/plugins/Cloudflare/v2/dataStreams/d1Queries.json +++ b/plugins/Cloudflare/v2/dataStreams/d1Queries.json @@ -11,7 +11,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$databaseId:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){d1QueriesAdaptiveGroups(limit:10000,filter:{databaseId:$databaseId,datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){count sum{rowsRead rowsWritten rowsReturned}quantiles{queryDurationMsP50 queryDurationMsP95 queryDurationMsP99}dimensions{datetime databaseRole}}}}}", + "query": "query($accountTag:string!,$databaseId:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){d1QueriesAdaptiveGroups(limit:10000,filter:{databaseId:$databaseId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){count sum{rowsRead rowsWritten rowsReturned}quantiles{queryDurationMsP50 queryDurationMsP95 queryDurationMsP99}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} databaseRole}}}}}", "variables": { "accountTag": "{{object.accountId}}", "databaseId": "{{object.rawId}}", @@ -85,10 +85,5 @@ "shape": "string" } ], - "timeframes": [ - "last12hours", - "last24hours", - "last7days", - "last30days" - ] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/d1Storage.json b/plugins/Cloudflare/v2/dataStreams/d1Storage.json index 1d63e765..1a957270 100644 --- a/plugins/Cloudflare/v2/dataStreams/d1Storage.json +++ b/plugins/Cloudflare/v2/dataStreams/d1Storage.json @@ -1,19 +1,19 @@ { "name": "d1Storage", "displayName": "D1 Storage", - "description": "Daily stored size of a D1 database", + "description": "Stored size of a D1 database", "tags": ["Database"], "baseDataSourceName": "httpRequestScopedSingle", "config": { "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$databaseId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){d1StorageAdaptiveGroups(limit:10000,filter:{databaseId:$databaseId,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){max{databaseSizeBytes}dimensions{date}}}}}", + "query": "query($accountTag:string!,$databaseId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){d1StorageAdaptiveGroups(limit:10000,filter:{databaseId:$databaseId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){max{databaseSizeBytes}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "databaseId": "{{object.rawId}}", - "start": "{{timeframe.start.split('T')[0]}}", - "end": "{{timeframe.end.split('T')[0]}}" + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" } }, "pathToData": "data.viewer.accounts.0.d1StorageAdaptiveGroups", @@ -34,7 +34,7 @@ "metadata": [ { "name": "dimensions.date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -45,5 +45,5 @@ "role": "value" } ], - "timeframes": ["last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/dmarcReports.json b/plugins/Cloudflare/v2/dataStreams/dmarcReports.json index 264e83e1..c108d4be 100644 --- a/plugins/Cloudflare/v2/dataStreams/dmarcReports.json +++ b/plugins/Cloudflare/v2/dataStreams/dmarcReports.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){dmarcReportsSourcesAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){sum{totalMatchingMessages dmarc} avg{dmarc} dimensions{date {{breakdown}}}}}}}", + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){dmarcReportsSourcesAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[sum_totalMatchingMessages_DESC]){sum{totalMatchingMessages dmarc} avg{dmarc} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "zoneTag": "{{object.rawId}}", "start": "{{timeframe.start}}", @@ -43,7 +43,7 @@ "metadata": [ { "name": "date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -65,5 +65,5 @@ "shape": ["percent", { "asZeroToOne": true }] } ], - "timeframes": ["last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json b/plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json index d7354406..9afa20fe 100644 --- a/plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json +++ b/plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){dnsFirewallAnalyticsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count quantiles{processingTimeUsP50} dimensions{date {{breakdown}}}}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){dnsFirewallAnalyticsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count quantiles{processingTimeUsP50} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "accountTag": "{{object.rawId}}", "start": "{{timeframe.start}}", @@ -43,7 +43,7 @@ "metadata": [ { "name": "date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -65,5 +65,5 @@ "shape": "milliseconds" } ], - "timeframes": ["last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/durableObjectInvocations.json b/plugins/Cloudflare/v2/dataStreams/durableObjectInvocations.json index fb565df8..ea14ba66 100644 --- a/plugins/Cloudflare/v2/dataStreams/durableObjectInvocations.json +++ b/plugins/Cloudflare/v2/dataStreams/durableObjectInvocations.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$namespaceId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){durableObjectsInvocationsAdaptiveGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){sum{requests errors responseBodySize wallTime}quantiles{wallTimeP50 wallTimeP90 wallTimeP99}dimensions{datetime status}}}}}", + "query": "query($accountTag:string!,$namespaceId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){durableObjectsInvocationsAdaptiveGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{requests errors responseBodySize wallTime}quantiles{wallTimeP50 wallTimeP90 wallTimeP99}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} status}}}}}", "variables": { "accountTag": "{{object.accountId}}", "namespaceId": "{{object.rawId}}", @@ -106,5 +106,5 @@ "shape": ["percent", { "decimalPlaces": 2 }] } ], - "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/durableObjectStorage.json b/plugins/Cloudflare/v2/dataStreams/durableObjectStorage.json index f8eb0f41..605f04d0 100644 --- a/plugins/Cloudflare/v2/dataStreams/durableObjectStorage.json +++ b/plugins/Cloudflare/v2/dataStreams/durableObjectStorage.json @@ -1,19 +1,19 @@ { "name": "durableObjectStorage", "displayName": "Durable Object Storage", - "description": "Daily stored size of a Durable Object namespace's SQLite storage", + "description": "Stored size of a Durable Object namespace's SQLite storage", "tags": ["Workers", "Storage"], "baseDataSourceName": "httpRequestScopedSingle", "config": { "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$namespaceId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){durableObjectsSqlStorageGroups(limit:10000,filter:{namespaceId:$namespaceId,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){max{storedBytes}dimensions{date}}}}}", + "query": "query($accountTag:string!,$namespaceId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){durableObjectsSqlStorageGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){max{storedBytes}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "namespaceId": "{{object.rawId}}", - "start": "{{timeframe.start.split('T')[0]}}", - "end": "{{timeframe.end.split('T')[0]}}" + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" } }, "pathToData": "data.viewer.accounts.0.durableObjectsSqlStorageGroups", @@ -34,7 +34,7 @@ "metadata": [ { "name": "dimensions.date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -45,5 +45,5 @@ "role": "value" } ], - "timeframes": ["last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/durableObjectSubrequests.json b/plugins/Cloudflare/v2/dataStreams/durableObjectSubrequests.json index 5449a3e0..cc5e40cf 100644 --- a/plugins/Cloudflare/v2/dataStreams/durableObjectSubrequests.json +++ b/plugins/Cloudflare/v2/dataStreams/durableObjectSubrequests.json @@ -11,7 +11,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$namespaceId:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){durableObjectsSubrequestsAdaptiveGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){sum{requestBodySizeUncached}dimensions{datetime}}}}}", + "query": "query($accountTag:string!,$namespaceId:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){durableObjectsSubrequestsAdaptiveGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{requestBodySizeUncached}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "namespaceId": "{{object.rawId}}", @@ -50,10 +50,5 @@ "role": "value" } ], - "timeframes": [ - "last12hours", - "last24hours", - "last7days", - "last30days" - ] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/emailRouting.json b/plugins/Cloudflare/v2/dataStreams/emailRouting.json index f3a0acf2..efa3e1c0 100644 --- a/plugins/Cloudflare/v2/dataStreams/emailRouting.json +++ b/plugins/Cloudflare/v2/dataStreams/emailRouting.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){emailRoutingAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count dimensions{date {{breakdown}}}}}}}", + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){emailRoutingAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "zoneTag": "{{object.rawId}}", "start": "{{timeframe.start}}", @@ -43,7 +43,7 @@ "metadata": [ { "name": "date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -60,5 +60,5 @@ "role": "value" } ], - "timeframes": ["last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json b/plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json index 63d93def..37138fc9 100644 --- a/plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json +++ b/plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayResolverQueriesAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date {{breakdown}} }}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayResolverQueriesAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", "variables": { "accountTag": "{{object.rawId}}", "start": "{{timeframe.start}}", @@ -43,7 +43,7 @@ "metadata": [ { "name": "date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -60,5 +60,5 @@ "role": "value" } ], - "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json b/plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json index c4aece5f..d031cb08 100644 --- a/plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json +++ b/plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json @@ -8,10 +8,10 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayL7RequestsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count dimensions{date {{breakdown}} }}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayL7RequestsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", "variables": { "accountTag": "{{object.rawId}}", - "start": "{{timeframe.start}}", + "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", "end": "{{timeframe.end}}" } }, @@ -45,7 +45,7 @@ "metadata": [ { "name": "date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -62,5 +62,5 @@ "role": "value" } ], - "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days"] } diff --git a/plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json b/plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json index 557ef356..ac97695d 100644 --- a/plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json +++ b/plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json @@ -8,10 +8,10 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayL4SessionsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date {{breakdown}} }}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayL4SessionsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", "variables": { "accountTag": "{{object.rawId}}", - "start": "{{timeframe.start}}", + "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", "end": "{{timeframe.end}}" } }, @@ -45,7 +45,7 @@ "metadata": [ { "name": "date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -62,5 +62,5 @@ "role": "value" } ], - "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days"] } diff --git a/plugins/Cloudflare/v2/dataStreams/graphqlQuery.json b/plugins/Cloudflare/v2/dataStreams/graphqlQuery.json index a0e8c790..6b25a54a 100644 --- a/plugins/Cloudflare/v2/dataStreams/graphqlQuery.json +++ b/plugins/Cloudflare/v2/dataStreams/graphqlQuery.json @@ -28,7 +28,7 @@ "name": "query", "label": "GraphQL query", "language": "graphql", - "help": "A query for the Cloudflare GraphQL Analytics API. These variables are always sent and can be declared in the query: `$start` / `$end` (`Time!`, ISO 8601, the selected timeframe) and `$startDate` / `$endDate` (`Date!`, `YYYY-MM-DD`). Cloudflare's scalar names are case sensitive - `string!` is lower case, `Time!` and `Date!` are not. Each analytics node has its own maximum query window and retention (as little as 1 day on some nodes), which is why only short timeframes are offered - for a longer or fixed window, select the **None** timeframe and write the dates into the query's own filter. See the [Cloudflare GraphQL Analytics docs](https://developers.cloudflare.com/analytics/graphql-api/).", + "help": "A query for the Cloudflare GraphQL Analytics API. These variables are always sent and can be declared in the query: `$start` / `$end` (`Time!`, ISO 8601, the selected timeframe) and `$startDate` / `$endDate` (`Date!`, `YYYY-MM-DD`). Cloudflare's scalar names are case sensitive - `string!` is lower case, `Time!` and `Date!` are not. Each analytics node has its own maximum query window and retention, which vary by Cloudflare plan (as little as 1 day on some nodes) - a wider timeframe fails with Cloudflare's error naming the limit. For a fixed window, select the **None** timeframe and write the dates into the query's own filter. See the [Cloudflare GraphQL Analytics docs](https://developers.cloudflare.com/analytics/graphql-api/).", "defaultValue": "query ($start: Time!, $end: Time!) {\n viewer {\n zones(limit: 1) {\n httpRequests1hGroups(\n limit: 1000\n filter: { datetime_geq: $start, datetime_leq: $end }\n orderBy: [datetime_ASC]\n ) {\n dimensions {\n datetime\n }\n sum {\n requests\n bytes\n cachedRequests\n threats\n }\n uniq {\n uniques\n }\n }\n }\n }\n}", "validation": { "required": true @@ -64,6 +64,14 @@ "none", "last1hour", "last12hours", - "last24hours" + "last24hours", + "last7days", + "last30days", + "thisMonth", + "lastMonth", + "thisQuarter", + "lastQuarter", + "thisYear", + "lastYear" ] } diff --git a/plugins/Cloudflare/v2/dataStreams/hyperdriveQueries.json b/plugins/Cloudflare/v2/dataStreams/hyperdriveQueries.json index b145e172..66fb0604 100644 --- a/plugins/Cloudflare/v2/dataStreams/hyperdriveQueries.json +++ b/plugins/Cloudflare/v2/dataStreams/hyperdriveQueries.json @@ -1,19 +1,19 @@ { "name": "hyperdriveQueries", "displayName": "Hyperdrive Queries", - "description": "Daily query count and query latency for a Hyperdrive config", + "description": "Query count and query latency for a Hyperdrive config", "tags": ["Database", "Analytics"], "baseDataSourceName": "httpRequestScopedSingle", "config": { "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$configId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){hyperdriveQueriesAdaptiveGroups(limit:10000,filter:{configId:$configId,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){count avg{queryLatency} dimensions{date}}}}}", + "query": "query($accountTag:string!,$configId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){hyperdriveQueriesAdaptiveGroups(limit:10000,filter:{configId:$configId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count avg{queryLatency} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "configId": "{{object.rawId}}", - "start": "{{timeframe.start.split('T')[0]}}", - "end": "{{timeframe.end.split('T')[0]}}" + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" } }, "pathToData": "data.viewer.accounts.0.hyperdriveQueriesAdaptiveGroups", @@ -34,7 +34,7 @@ "metadata": [ { "name": "dimensions.date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -50,5 +50,5 @@ "shape": "milliseconds" } ], - "timeframes": ["last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/imagesRequests.json b/plugins/Cloudflare/v2/dataStreams/imagesRequests.json index 347c791b..82223801 100644 --- a/plugins/Cloudflare/v2/dataStreams/imagesRequests.json +++ b/plugins/Cloudflare/v2/dataStreams/imagesRequests.json @@ -1,14 +1,14 @@ { "name": "imagesRequests", "displayName": "Images Requests", - "description": "Daily Cloudflare Images request counts for an account", + "description": "Cloudflare Images request counts for an account", "tags": ["Media"], "baseDataSourceName": "httpRequestScopedSingle", "config": { "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){imagesRequestsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){sum{requests}dimensions{date}}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){imagesRequestsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){sum{requests}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { "accountTag": "{{object.rawId}}", "start": "{{timeframe.start}}", @@ -29,7 +29,7 @@ "metadata": [ { "name": "date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -40,5 +40,5 @@ "role": "value" } ], - "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/imagesTransformations.json b/plugins/Cloudflare/v2/dataStreams/imagesTransformations.json index dec2be8f..aeee4a94 100644 --- a/plugins/Cloudflare/v2/dataStreams/imagesTransformations.json +++ b/plugins/Cloudflare/v2/dataStreams/imagesTransformations.json @@ -40,5 +40,5 @@ "role": "value" } ], - "timeframes": ["last7days", "last30days"] + "timeframes": ["last7days", "last30days", "thisMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/kvOperations.json b/plugins/Cloudflare/v2/dataStreams/kvOperations.json index 50ef33d1..7499da51 100644 --- a/plugins/Cloudflare/v2/dataStreams/kvOperations.json +++ b/plugins/Cloudflare/v2/dataStreams/kvOperations.json @@ -1,19 +1,19 @@ { "name": "kvOperations", "displayName": "KV Operations", - "description": "Daily read, write, delete and list operation counts and latency for a Workers KV namespace", + "description": "Read, write, delete and list operation counts and latency for a Workers KV namespace", "tags": ["Storage", "Analytics"], "baseDataSourceName": "httpRequestScopedSingle", "config": { "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$namespaceId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){kvOperationsAdaptiveGroups(limit:10000,filter:{namespaceId:$namespaceId,date_geq:$start,date_leq:$end},orderBy:[date_DESC]){sum{requests}dimensions{date actionType}quantiles{latencyMsP50 latencyMsP90 latencyMsP99}}}}}", + "query": "query($accountTag:string!,$namespaceId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){kvOperationsAdaptiveGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_DESC]){sum{requests}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} actionType}quantiles{latencyMsP50 latencyMsP90 latencyMsP99}}}}}", "variables": { "accountTag": "{{object.accountId}}", "namespaceId": "{{object.rawId}}", - "start": "{{timeframe.start.split('T')[0]}}", - "end": "{{timeframe.end.split('T')[0]}}" + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" } }, "pathToData": "data.viewer.accounts.0.kvOperationsAdaptiveGroups", @@ -30,7 +30,7 @@ "metadata": [ { "name": "dimensions.date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -62,5 +62,5 @@ "shape": "milliseconds" } ], - "timeframes": ["last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/kvStorage.json b/plugins/Cloudflare/v2/dataStreams/kvStorage.json index 98aba56d..30039b5a 100644 --- a/plugins/Cloudflare/v2/dataStreams/kvStorage.json +++ b/plugins/Cloudflare/v2/dataStreams/kvStorage.json @@ -1,19 +1,19 @@ { "name": "kvStorage", "displayName": "KV Storage", - "description": "Daily stored key count and byte size for a Workers KV namespace", + "description": "Stored key count and byte size for a Workers KV namespace", "tags": ["Storage"], "baseDataSourceName": "httpRequestScopedSingle", "config": { "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$namespaceId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){kvStorageAdaptiveGroups(filter:{namespaceId:$namespaceId,date_geq:$start,date_leq:$end},limit:10000,orderBy:[date_DESC]){max{keyCount byteCount}dimensions{date}}}}}", + "query": "query($accountTag:string!,$namespaceId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){kvStorageAdaptiveGroups(filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},limit:10000,orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_DESC]){max{keyCount byteCount}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "namespaceId": "{{object.rawId}}", - "start": "{{timeframe.start.split('T')[0]}}", - "end": "{{timeframe.end.split('T')[0]}}" + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" } }, "pathToData": "data.viewer.accounts.0.kvStorageAdaptiveGroups", @@ -30,7 +30,7 @@ "metadata": [ { "name": "dimensions.date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -46,5 +46,5 @@ "shape": "bytes" } ], - "timeframes": ["last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/pagesFunctionsInvocations.json b/plugins/Cloudflare/v2/dataStreams/pagesFunctionsInvocations.json index d8518fc4..dbdb3b6e 100644 --- a/plugins/Cloudflare/v2/dataStreams/pagesFunctionsInvocations.json +++ b/plugins/Cloudflare/v2/dataStreams/pagesFunctionsInvocations.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){pagesFunctionsInvocationsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){sum{requests errors subrequests}quantiles{cpuTimeP50 cpuTimeP99}dimensions{datetime scriptName status}}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){pagesFunctionsInvocationsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{requests errors subrequests}quantiles{cpuTimeP50 cpuTimeP99}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} scriptName status}}}}}", "variables": { "accountTag": "{{object.rawId}}", "start": "{{timeframe.start}}", @@ -74,5 +74,5 @@ "shape": ["milliseconds", { "decimalPlaces": 2 }] } ], - "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/pipelineIngestion.json b/plugins/Cloudflare/v2/dataStreams/pipelineIngestion.json index ffd25320..dd360cff 100644 --- a/plugins/Cloudflare/v2/dataStreams/pipelineIngestion.json +++ b/plugins/Cloudflare/v2/dataStreams/pipelineIngestion.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$pipelineId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){pipelinesIngestionAdaptiveGroups(limit:10000,filter:{pipelineId:$pipelineId,datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count sum{ingestedBytes ingestedRecords} dimensions{date}}}}}", + "query": "query($accountTag:string!,$pipelineId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){pipelinesIngestionAdaptiveGroups(limit:10000,filter:{pipelineId:$pipelineId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count sum{ingestedBytes ingestedRecords} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "pipelineId": "{{object.rawId}}", @@ -34,7 +34,7 @@ "metadata": [ { "name": "dimensions.date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -55,5 +55,5 @@ "shape": "number" } ], - "timeframes": ["last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/queueBacklog.json b/plugins/Cloudflare/v2/dataStreams/queueBacklog.json index 1c9a03ac..e6d90d60 100644 --- a/plugins/Cloudflare/v2/dataStreams/queueBacklog.json +++ b/plugins/Cloudflare/v2/dataStreams/queueBacklog.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$queueId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){queueBacklogAdaptiveGroups(limit:10000,filter:{queueId:$queueId,datetime_geq:$start,datetime_leq:$end},orderBy:[datetimeHour_ASC]){avg{messages bytes}dimensions{datetimeHour}}}}}", + "query": "query($accountTag:string!,$queueId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){queueBacklogAdaptiveGroups(limit:10000,filter:{queueId:$queueId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){avg{messages bytes}dimensions{datetimeHour: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "queueId": "{{object.rawId}}", @@ -47,5 +47,5 @@ "shape": "bytes" } ], - "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/queueConsumerMetrics.json b/plugins/Cloudflare/v2/dataStreams/queueConsumerMetrics.json index 806a8974..8d8c0836 100644 --- a/plugins/Cloudflare/v2/dataStreams/queueConsumerMetrics.json +++ b/plugins/Cloudflare/v2/dataStreams/queueConsumerMetrics.json @@ -11,7 +11,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$queueId:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){queueConsumerMetricsAdaptiveGroups(limit:10000,filter:{queueId:$queueId,datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){avg{concurrency}dimensions{datetime}}}}}", + "query": "query($accountTag:string!,$queueId:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){queueConsumerMetricsAdaptiveGroups(limit:10000,filter:{queueId:$queueId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){avg{concurrency}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "queueId": "{{object.rawId}}", @@ -50,10 +50,5 @@ "role": "value" } ], - "timeframes": [ - "last12hours", - "last24hours", - "last7days", - "last30days" - ] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/queueMessageOperations.json b/plugins/Cloudflare/v2/dataStreams/queueMessageOperations.json index 718141fc..7f9a64af 100644 --- a/plugins/Cloudflare/v2/dataStreams/queueMessageOperations.json +++ b/plugins/Cloudflare/v2/dataStreams/queueMessageOperations.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$queueId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){queueMessageOperationsAdaptiveGroups(limit:10000,filter:{queueId:$queueId,datetime_geq:$start,datetime_leq:$end},orderBy:[datetimeHour_ASC]){count sum{billableOperations bytes}avg{lagTime retryCount}max{messageSize}dimensions{datetimeHour actionType outcome consumerType}}}}}", + "query": "query($accountTag:string!,$queueId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){queueMessageOperationsAdaptiveGroups(limit:10000,filter:{queueId:$queueId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){count sum{billableOperations bytes}avg{lagTime retryCount}max{messageSize}dimensions{datetimeHour: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} actionType outcome consumerType}}}}}", "variables": { "accountTag": "{{object.accountId}}", "queueId": "{{object.rawId}}", @@ -91,5 +91,5 @@ "shape": "bytes" } ], - "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/r2Operations.json b/plugins/Cloudflare/v2/dataStreams/r2Operations.json index 90fe40ea..27f8b57a 100644 --- a/plugins/Cloudflare/v2/dataStreams/r2Operations.json +++ b/plugins/Cloudflare/v2/dataStreams/r2Operations.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$bucketName:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){r2OperationsAdaptiveGroups(limit:10000,filter:{bucketName:$bucketName,datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){sum{requests responseBytes}dimensions{datetime actionType actionStatus}}}}}", + "query": "query($accountTag:string!,$bucketName:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){r2OperationsAdaptiveGroups(limit:10000,filter:{bucketName:$bucketName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : 'date' }}_ASC]){sum{requests responseBytes}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : 'date' }} actionType actionStatus}}}}}", "variables": { "accountTag": "{{object.accountId}}", "bucketName": "{{object.name}}", @@ -58,5 +58,5 @@ "shape": "bytes" } ], - "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/r2Storage.json b/plugins/Cloudflare/v2/dataStreams/r2Storage.json index 370b7029..561eaa17 100644 --- a/plugins/Cloudflare/v2/dataStreams/r2Storage.json +++ b/plugins/Cloudflare/v2/dataStreams/r2Storage.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$bucketName:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){r2StorageAdaptiveGroups(limit:10000,filter:{bucketName:$bucketName,datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){max{objectCount payloadSize metadataSize uploadCount}dimensions{datetime}}}}}", + "query": "query($accountTag:string!,$bucketName:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){r2StorageAdaptiveGroups(limit:10000,filter:{bucketName:$bucketName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){max{objectCount payloadSize metadataSize uploadCount}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "bucketName": "{{object.name}}", @@ -57,5 +57,5 @@ "shape": "number" } ], - "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/realtimeUsage.json b/plugins/Cloudflare/v2/dataStreams/realtimeUsage.json index 1c931ffa..e4573783 100644 --- a/plugins/Cloudflare/v2/dataStreams/realtimeUsage.json +++ b/plugins/Cloudflare/v2/dataStreams/realtimeUsage.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$appId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){callsUsageAdaptiveGroups(limit:10000,filter:{appId:$appId,datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){sum{egressBytes ingressBytes} dimensions{date trackType}}}}}", + "query": "query($accountTag:string!,$appId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){callsUsageAdaptiveGroups(limit:10000,filter:{appId:$appId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){sum{egressBytes ingressBytes} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} trackType}}}}}", "variables": { "accountTag": "{{object.accountId}}", "appId": "{{object.rawId}}", @@ -34,7 +34,7 @@ "metadata": [ { "name": "dimensions.date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -56,5 +56,5 @@ "shape": "bytes" } ], - "timeframes": ["last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json b/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json index b5b46ebe..f57196c9 100644 --- a/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json +++ b/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!,$requestHost:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumPageloadEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end,requestHost_like:$requestHost},orderBy:[count_DESC]){count sum{visits} dimensions{date {{breakdown}} }}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$requestHost:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumPageloadEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end,requestHost_like:$requestHost},orderBy:[count_DESC]){count sum{visits} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", "variables": { "accountTag": "{{object.accountId}}", "start": "{{timeframe.start}}", @@ -45,7 +45,7 @@ "metadata": [ { "name": "date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -67,5 +67,14 @@ "shape": "number" } ], - "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth", + "lastMonth", + "thisQuarter" + ] } diff --git a/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json b/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json index a498d83b..38ef5759 100644 --- a/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json +++ b/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json @@ -1,14 +1,14 @@ { "name": "rumWebVitals", "displayName": "Core Web Vitals", - "description": "Daily P75 Core Web Vitals (LCP, INP/FID, CLS) and RUM sample counts for a zone's hostnames", + "description": "P75 Core Web Vitals (LCP, INP/FID, CLS) and RUM sample counts for a zone's hostnames", "tags": ["Zone", "Analytics"], "baseDataSourceName": "httpRequestScopedSingle", "config": { "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!,$hostFilter:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumWebVitalsEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end,requestHost_like:$hostFilter},orderBy:[date_ASC]){count dimensions{date} quantiles{largestContentfulPaintP75 interactionToNextPaintP75 firstInputDelayP75 cumulativeLayoutShiftP75}}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$hostFilter:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumWebVitalsEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end,requestHost_like:$hostFilter},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}} quantiles{largestContentfulPaintP75 interactionToNextPaintP75 firstInputDelayP75 cumulativeLayoutShiftP75}}}}}", "variables": { "accountTag": "{{object.accountId}}", "start": "{{timeframe.start}}", @@ -30,7 +30,7 @@ "metadata": [ { "name": "dimensions.date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -78,5 +78,14 @@ "shape": "number" } ], - "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth", + "lastMonth", + "thisQuarter" + ] } diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/zoneFirewallEvents.js b/plugins/Cloudflare/v2/dataStreams/scripts/zoneFirewallEvents.js index bd7759ab..cf1c1391 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/zoneFirewallEvents.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/zoneFirewallEvents.js @@ -2,7 +2,31 @@ // postRequestScript bypasses the stream's declarative errorHandling entirely, // so the error is raised here or it would be swallowed into an empty result. if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); + const message = data.errors[0].message || ""; + // The range and history Cloudflare allows for firewall events depend on the zone's + // plan, so the stream offers timeframes only higher plans can serve. When a plan's + // limit rejects one, say so rather than surfacing the raw quota error alone. + // String methods rather than a regex: backslash escapes do not survive into the + // deployed script. + const limitText = (marker, lead) => { + const at = message.indexOf(marker); + if (at < 0) return null; + const rest = message.slice(at + marker.length).trim(); + return lead + rest.split(" ")[0].split(",")[0]; + }; + const limit = + limitText("cannot request a time range wider than", "a range of ") || + limitText("cannot request data older than", "the last "); + if (limit) { + throw new Error( + "Cloudflare's plan for this zone limits firewall events to " + + limit + + ". Choose a shorter timeframe - longer ranges need a higher Cloudflare plan. (" + + message + + ")" + ); + } + throw new Error("Cloudflare GraphQL error: " + message); } // dataStreams/scripts/zoneFirewallEvents.js diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/zoneTraffic.js b/plugins/Cloudflare/v2/dataStreams/scripts/zoneTraffic.js index dbc7ef2b..0ae5268f 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/zoneTraffic.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/zoneTraffic.js @@ -10,6 +10,10 @@ if (data && data.errors && data.errors.length) { // scoped to several zones cannot tell which rows belong to which zone. Stamp the // scoped zone's tag and name onto every row so tiles and SQL can group by zone. // Column names keep the dotted form the previous expandInnerObjects config produced. +// +// The query reads httpRequests1hGroups for short timeframes and httpRequests1dGroups +// for long ones (the hourly dataset is capped at 3 days), aliasing either to `rows`. +// On the daily dataset dimensions.datetime holds a YYYY-MM-DD date. const zone = (context.objects && context.objects[0]) || {}; const zoneTag = zone.rawId || ""; @@ -21,7 +25,7 @@ const groups = data.data.viewer && data.data.viewer.zones && data.data.viewer.zones[0] && - data.data.viewer.zones[0].httpRequests1hGroups) || + data.data.viewer.zones[0].rows) || []; result = groups.map((row) => { diff --git a/plugins/Cloudflare/v2/dataStreams/streamCmcd.json b/plugins/Cloudflare/v2/dataStreams/streamCmcd.json index faa8c66d..b2323bf3 100644 --- a/plugins/Cloudflare/v2/dataStreams/streamCmcd.json +++ b/plugins/Cloudflare/v2/dataStreams/streamCmcd.json @@ -1,19 +1,19 @@ { "name": "streamCmcd", "displayName": "Stream Playback Quality", - "description": "Daily playback quality metrics for a Cloudflare Stream video, grouped by a selectable dimension", + "description": "Playback quality metrics for a Cloudflare Stream video, grouped by a selectable dimension", "tags": ["Media"], "baseDataSourceName": "httpRequestScopedSingle", "config": { "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$videoId:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){streamCMCDAdaptiveGroups(limit:10000,filter:{videoId:$videoId,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){count avg{bufferStarvationDuration initialBufferStarvationDuration encodedBitrate} dimensions{date {{breakdown}}}}}}}", + "query": "query($accountTag:string!,$videoId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){streamCMCDAdaptiveGroups(limit:10000,filter:{videoId:$videoId,datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count avg{bufferStarvationDuration initialBufferStarvationDuration encodedBitrate} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "videoId": "{{object.rawId}}", - "start": "{{timeframe.start.split('T')[0]}}", - "end": "{{timeframe.end.split('T')[0]}}" + "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", + "end": "{{timeframe.end}}" } }, "postRequestScript": "streamCmcd.js", @@ -47,7 +47,7 @@ "metadata": [ { "name": "date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -79,5 +79,5 @@ "shape": "number" } ], - "timeframes": ["last24hours", "last7days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days"] } diff --git a/plugins/Cloudflare/v2/dataStreams/streamMinutesViewed.json b/plugins/Cloudflare/v2/dataStreams/streamMinutesViewed.json index 2ad823cd..25f1f84b 100644 --- a/plugins/Cloudflare/v2/dataStreams/streamMinutesViewed.json +++ b/plugins/Cloudflare/v2/dataStreams/streamMinutesViewed.json @@ -1,19 +1,19 @@ { "name": "streamMinutesViewed", "displayName": "Stream Minutes Viewed", - "description": "Daily minutes of video viewed for a Cloudflare Stream video", + "description": "Minutes of video viewed for a Cloudflare Stream video", "tags": ["Media"], "baseDataSourceName": "httpRequestScopedSingle", "config": { "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$uid:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){streamMinutesViewedAdaptiveGroups(limit:10000,filter:{uid:$uid,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){dimensions{date}sum{minutesViewed}}}}}", + "query": "query($accountTag:string!,$uid:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){streamMinutesViewedAdaptiveGroups(limit:10000,filter:{uid:$uid,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}sum{minutesViewed}}}}}", "variables": { "accountTag": "{{object.accountId}}", "uid": "{{object.rawId}}", - "start": "{{timeframe.start.split('T')[0]}}", - "end": "{{timeframe.end.split('T')[0]}}" + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" } }, "pathToData": "data.viewer.accounts.0.streamMinutesViewedAdaptiveGroups", @@ -34,7 +34,7 @@ "metadata": [ { "name": "dimensions.date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -45,5 +45,5 @@ "role": "value" } ], - "timeframes": ["last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json b/plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json index 2bbfb144..7e0fbaf6 100644 --- a/plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json +++ b/plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$siteKey:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){turnstileAdaptiveGroups(limit:5000,filter:{siteKey:$siteKey,datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count dimensions{date {{breakdown}}}}}}}", + "query": "query($accountTag:string!,$siteKey:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){turnstileAdaptiveGroups(limit:5000,filter:{siteKey:$siteKey,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "siteKey": "{{object.rawId}}", @@ -42,7 +42,7 @@ "metadata": [ { "name": "date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, diff --git a/plugins/Cloudflare/v2/dataStreams/vectorizeQueries.json b/plugins/Cloudflare/v2/dataStreams/vectorizeQueries.json index d6a2748d..a2e065a6 100644 --- a/plugins/Cloudflare/v2/dataStreams/vectorizeQueries.json +++ b/plugins/Cloudflare/v2/dataStreams/vectorizeQueries.json @@ -1,19 +1,19 @@ { "name": "vectorizeQueries", "displayName": "Vectorize Queries", - "description": "Daily query count and query latency for a Vectorize index", + "description": "Query count and query latency for a Vectorize index", "tags": ["Database", "Analytics"], "baseDataSourceName": "httpRequestScopedSingle", "config": { "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$indexName:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){vectorizeV2QueriesAdaptiveGroups(limit:10000,filter:{indexName:$indexName,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){count avg{requestDurationMs} dimensions{date}}}}}", + "query": "query($accountTag:string!,$indexName:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){vectorizeV2QueriesAdaptiveGroups(limit:10000,filter:{indexName:$indexName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count avg{requestDurationMs} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "indexName": "{{object.name}}", - "start": "{{timeframe.start.split('T')[0]}}", - "end": "{{timeframe.end.split('T')[0]}}" + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" } }, "pathToData": "data.viewer.accounts.0.vectorizeV2QueriesAdaptiveGroups", @@ -34,7 +34,7 @@ "metadata": [ { "name": "dimensions.date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -50,5 +50,5 @@ "shape": "milliseconds" } ], - "timeframes": ["last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/vectorizeStorage.json b/plugins/Cloudflare/v2/dataStreams/vectorizeStorage.json index bea67517..b809eafc 100644 --- a/plugins/Cloudflare/v2/dataStreams/vectorizeStorage.json +++ b/plugins/Cloudflare/v2/dataStreams/vectorizeStorage.json @@ -1,19 +1,19 @@ { "name": "vectorizeStorage", "displayName": "Vectorize Storage", - "description": "Daily stored vector count and dimensionality for a Vectorize index", + "description": "Stored vector count and dimensionality for a Vectorize index", "tags": ["Database", "Storage"], "baseDataSourceName": "httpRequestScopedSingle", "config": { "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$indexName:string,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){vectorizeV2StorageAdaptiveGroups(limit:10000,filter:{indexName:$indexName,date_geq:$start,date_leq:$end},orderBy:[date_ASC]){max{storedVectorDimensions vectorCount} dimensions{date}}}}}", + "query": "query($accountTag:string!,$indexName:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){vectorizeV2StorageAdaptiveGroups(limit:10000,filter:{indexName:$indexName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){max{storedVectorDimensions vectorCount} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "indexName": "{{object.name}}", - "start": "{{timeframe.start.split('T')[0]}}", - "end": "{{timeframe.end.split('T')[0]}}" + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" } }, "pathToData": "data.viewer.accounts.0.vectorizeV2StorageAdaptiveGroups", @@ -34,7 +34,7 @@ "metadata": [ { "name": "dimensions.date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -50,5 +50,5 @@ "shape": "number" } ], - "timeframes": ["last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/workerInvocations.json b/plugins/Cloudflare/v2/dataStreams/workerInvocations.json index 16a6173f..1332fa2c 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerInvocations.json +++ b/plugins/Cloudflare/v2/dataStreams/workerInvocations.json @@ -11,7 +11,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$scriptName:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){workersInvocationsAdaptive(limit:10000,filter:{scriptName:$scriptName,datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){sum{requests errors subrequests}quantiles{cpuTimeP50 cpuTimeP99}dimensions{datetime status scriptName}}}}}", + "query": "query($accountTag:string!,$scriptName:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){workersInvocationsAdaptive(limit:10000,filter:{scriptName:$scriptName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{requests errors subrequests}quantiles{cpuTimeP50 cpuTimeP99}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} status scriptName}}}}}", "variables": { "accountTag": "{{object.accountId}}", "scriptName": "{{object.name}}", @@ -97,10 +97,5 @@ "shape": ["percent", { "decimalPlaces": 2 }] } ], - "timeframes": [ - "last12hours", - "last24hours", - "last7days", - "last30days" - ] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth", "lastMonth"] } \ No newline at end of file diff --git a/plugins/Cloudflare/v2/dataStreams/workersAiInference.json b/plugins/Cloudflare/v2/dataStreams/workersAiInference.json index 209b68fc..39656770 100644 --- a/plugins/Cloudflare/v2/dataStreams/workersAiInference.json +++ b/plugins/Cloudflare/v2/dataStreams/workersAiInference.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiInferenceAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count sum{totalInputTokens totalOutputTokens totalInferenceTimeMs}dimensions{date {{breakdown}}}}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiInferenceAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count sum{totalInputTokens totalOutputTokens totalInferenceTimeMs}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "accountTag": "{{object.rawId}}", "start": "{{timeframe.start}}", @@ -42,7 +42,7 @@ "metadata": [ { "name": "date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -74,5 +74,5 @@ "shape": ["milliseconds", { "decimalPlaces": 2 }] } ], - "timeframes": ["last12hours", "last24hours", "last7days", "last30days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days", "thisMonth"] } diff --git a/plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json b/plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json index 5122ab86..f326e606 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json @@ -8,10 +8,10 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){dnsAnalyticsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count avg{processingTimeUs} dimensions{date {{breakdown}}}}}}}", + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){dnsAnalyticsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count avg{processingTimeUs} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "zoneTag": "{{object.rawId}}", - "start": "{{timeframe.start}}", + "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", "end": "{{timeframe.end}}" } }, @@ -43,7 +43,7 @@ "metadata": [ { "name": "date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -65,5 +65,5 @@ "shape": "milliseconds" } ], - "timeframes": ["last12hours", "last24hours", "last7days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days"] } diff --git a/plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json index 3b2151c5..93c05b0b 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json @@ -11,7 +11,7 @@ "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){firewallEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{action {{breakdown}} }}}}}", "variables": { "zoneTag": "{{object.rawId}}", - "start": "{{timeframe.start}}", + "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", "end": "{{timeframe.end}}" } }, @@ -77,5 +77,5 @@ "role": "value" } ], - "timeframes": ["last12hours", "last24hours"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days"] } diff --git a/plugins/Cloudflare/v2/dataStreams/zoneHealthCheckEvents.json b/plugins/Cloudflare/v2/dataStreams/zoneHealthCheckEvents.json index aa04d660..60c04d45 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneHealthCheckEvents.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneHealthCheckEvents.json @@ -8,10 +8,10 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){healthCheckEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){count avg{rttMs}dimensions{datetime healthCheckName healthCheckId healthStatus healthChanged failureReason region originIP}}}}}", + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){healthCheckEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count avg{rttMs}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} healthCheckName healthCheckId healthStatus healthChanged failureReason region originIP}}}}}", "variables": { "zoneTag": "{{object.rawId}}", - "start": "{{timeframe.start}}", + "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", "end": "{{timeframe.end}}" } }, diff --git a/plugins/Cloudflare/v2/dataStreams/zoneLoadBalancing.json b/plugins/Cloudflare/v2/dataStreams/zoneLoadBalancing.json index 27919ee9..e503fb18 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneLoadBalancing.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneLoadBalancing.json @@ -11,7 +11,7 @@ "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){loadBalancingRequestsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{lbName selectedPoolName selectedOriginName coloCode}}}}}", "variables": { "zoneTag": "{{object.rawId}}", - "start": "{{timeframe.start}}", + "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", "end": "{{timeframe.end}}" } }, @@ -55,5 +55,5 @@ "role": "value" } ], - "timeframes": ["last12hours", "last24hours"] + "timeframes": ["last1hour", "last12hours", "last24hours"] } diff --git a/plugins/Cloudflare/v2/dataStreams/zoneNelReports.json b/plugins/Cloudflare/v2/dataStreams/zoneNelReports.json index a8746d0c..bcb36438 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneNelReports.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneNelReports.json @@ -8,10 +8,10 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){nelReportsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count dimensions{date {{breakdown}}}}}}}", + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){nelReportsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "zoneTag": "{{object.rawId}}", - "start": "{{timeframe.start}}", + "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", "end": "{{timeframe.end}}" } }, @@ -43,7 +43,7 @@ "metadata": [ { "name": "date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -60,5 +60,5 @@ "role": "value" } ], - "timeframes": ["last24hours", "last7days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days"] } diff --git a/plugins/Cloudflare/v2/dataStreams/zonePageShield.json b/plugins/Cloudflare/v2/dataStreams/zonePageShield.json index 3f7d91d9..8fbf35f4 100644 --- a/plugins/Cloudflare/v2/dataStreams/zonePageShield.json +++ b/plugins/Cloudflare/v2/dataStreams/zonePageShield.json @@ -8,10 +8,10 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){pageShieldReportsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[date_ASC]){count dimensions{date {{breakdown}}}}}}}", + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){pageShieldReportsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "zoneTag": "{{object.rawId}}", - "start": "{{timeframe.start}}", + "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", "end": "{{timeframe.end}}" } }, @@ -43,7 +43,7 @@ "metadata": [ { "name": "date", - "displayName": "Date", + "displayName": "Time", "shape": "date", "role": "timestamp" }, @@ -60,5 +60,5 @@ "role": "value" } ], - "timeframes": ["last24hours", "last7days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days"] } diff --git a/plugins/Cloudflare/v2/dataStreams/zoneTraffic.json b/plugins/Cloudflare/v2/dataStreams/zoneTraffic.json index 04e979fb..df15f906 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneTraffic.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneTraffic.json @@ -1,7 +1,7 @@ { "name": "zoneTraffic", "displayName": "Zone Traffic", - "description": "Hourly HTTP request, cache and bandwidth totals for a zone", + "description": "HTTP request, cache and bandwidth totals for a zone (hourly up to 2 days, daily beyond)", "tags": [ "Zone", "Analytics" @@ -11,11 +11,11 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){httpRequests1hGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_ASC]){dimensions{datetime}sum{requests cachedRequests bytes cachedBytes threats pageViews encryptedRequests}uniq{uniques}}}}}", + "query": "query($zoneTag:string!,$start:{{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'Time!' : 'Date!' }},$end:{{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'Time!' : 'Date!' }}){viewer{zones(filter:{zoneTag:$zoneTag}){rows: {{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'httpRequests1hGroups' : 'httpRequests1dGroups' }}(limit:10000,filter:{ {{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'datetime' : 'date' }}_geq:$start, {{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'datetime' : 'date' }}_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'datetime' : 'date' }}_ASC]){dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'datetime' : 'date' }}}sum{requests cachedRequests bytes cachedBytes threats pageViews encryptedRequests}uniq{uniques}}}}}", "variables": { "zoneTag": "{{object.rawId}}", - "start": "{{timeframe.start}}", - "end": "{{timeframe.end}}" + "start": "{{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? timeframe.start : timeframe.start.split('T')[0] }}", + "end": "{{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? timeframe.end : new Date((timeframe.unixEnd - 1) * 1000).toISOString().split('T')[0] }}" } }, "postRequestScript": "zoneTraffic.js", @@ -106,6 +106,13 @@ ], "timeframes": [ "last12hours", - "last24hours" + "last24hours", + "last7days", + "last30days", + "thisMonth", + "lastMonth", + "thisQuarter", + "lastQuarter", + "thisYear" ] } \ No newline at end of file diff --git a/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json b/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json index ec1c4176..37889c29 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json @@ -11,7 +11,7 @@ "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){httpRequestsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count sum{edgeResponseBytes visits} dimensions{ {{breakdown}} }}}}}", "variables": { "zoneTag": "{{object.rawId}}", - "start": "{{timeframe.start}}", + "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", "end": "{{timeframe.end}}" } }, @@ -67,5 +67,5 @@ "shape": "number" } ], - "timeframes": ["last12hours", "last24hours", "last7days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days"] } diff --git a/plugins/Cloudflare/v2/docs/README.md b/plugins/Cloudflare/v2/docs/README.md index a1f73107..d41fdd33 100644 --- a/plugins/Cloudflare/v2/docs/README.md +++ b/plugins/Cloudflare/v2/docs/README.md @@ -66,7 +66,7 @@ The out-of-the-box dashboards open with a **Cloudflare Overview**, with perspect ## Data streams -- **Zone Traffic** - hourly requests, bandwidth, cached traffic, threats, page views and cache hit ratio for a zone. +- **Zone Traffic** - requests, bandwidth, cached traffic, threats, page views and cache hit ratio for a zone, hourly for timeframes up to two days and daily beyond. - **Zone Traffic Breakdown** - requests, bytes and visits for a zone grouped by a dimension you choose (country, status code, cache status, host, device type, HTTP protocol or content type). - **Zone Firewall Events** - firewall and WAF event counts for a zone by action, grouped by rule, service, country, host, user agent or path. - **Load Balancing Requests** - load balancer request counts for a zone by load balancer, pool, origin and edge location. @@ -76,16 +76,16 @@ The out-of-the-box dashboards open with a **Cloudflare Overview**, with perspect - **Worker Invocations** - requests, errors, subrequests and CPU-time percentiles for one Worker script. - **R2 Operations** - requests and response bytes against an R2 bucket by operation type and outcome. - **R2 Storage** - stored object count, payload size, metadata size and upload count for an R2 bucket over time. -- **KV Operations** - daily request counts and latency percentiles for a KV namespace by operation type. -- **KV Storage** - daily stored key count and byte size for a KV namespace. -- **D1 Queries** - daily read and write query counts, rows read and written, response bytes and query-time percentiles for a D1 database. -- **D1 Storage** - daily stored size of a D1 database. +- **KV Operations** - request counts and latency percentiles for a KV namespace by operation type. +- **KV Storage** - stored key count and byte size for a KV namespace. +- **D1 Queries** - read and write query counts, rows read and written, response bytes and query-time percentiles for a D1 database. +- **D1 Storage** - stored size of a D1 database. - **Queue Message Operations** - message write, read and delete operations on a queue with outcome, consumer type, lag time and retry count. - **Queue Backlog** - average messages and bytes waiting in a queue over time. - **Pages Deployments** - deployment history for a Pages project with environment, status, branch, commit and URL. - **Tunnel Connections** - active connector connections for a Tunnel with edge location, origin IP, connector version and architecture. - **Load Balancer Pool Health** - per-origin health, response code, response time and failure reason for a pool at each Cloudflare edge location. -- **Access Logins** - daily Zero Trust login attempts for an Access application by identity provider, country and outcome. +- **Access Logins** - Zero Trust login attempts for an Access application by identity provider, country and outcome. - **DNS Analytics** - authoritative DNS query volume and response time for a zone, grouped by query name, query type, response code or edge location. - **Email Routing** - forwarded and rejected messages for a zone by action, status and rule. - **DMARC Reports** - DMARC alignment for a zone by sending source, with pass rate and message volume. @@ -112,7 +112,7 @@ The out-of-the-box dashboards open with a **Cloudflare Overview**, with perspect - **Images Unique Transformations** - daily count of unique image transformations served for an account. - **Pages Functions Invocations** - requests, errors and CPU time for the Pages Functions running in an account, by function. - **Browser Rendering** - Browser Rendering session count and duration for an account. -- **Stream Minutes Viewed** - daily minutes viewed for a Cloudflare Stream video. +- **Stream Minutes Viewed** - minutes viewed for a Cloudflare Stream video. - **Stream Playback Quality** - playback buffering and bitrate for a Stream video, by country, resolution or stream type. - **Realtime Usage** - ingress and egress bandwidth for a Realtime application by track type. - **Turnstile Challenges** - challenges served by a Turnstile widget, by event type or action. @@ -193,23 +193,40 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w - **One-to-many relationships only correlate on their first value.** The import serialises an array-valued property to a JSON string (`["a.com","b.com"]`) rather than storing it as a multi-valued property, and correlation conditions only offer `equals`, so an array can never match a scalar. Where a Cloudflare object names several others - a Turnstile widget's allowed domains, a Pages project's custom domains, a queue's consumers and producers - the plugin stores the full list as a readable string for display and a separate `primary*` property holding the first entry, and correlates on that. A widget covering three zones therefore draws an edge to one of them. The same constraint is why Kubernetes, the only other plugin here shipping correlation rules, joins on `primaryBackendServiceName` rather than the full backend list. -- **Analytics timeframes are capped per dataset, and the caps are short.** Cloudflare's GraphQL Analytics API limits how wide a single query's time range can be, and the limit differs for every dataset. These were measured against a Pro-plan account: - - | Widest single query | Data streams | - | ------------------- | ------------ | - | **1 day** | Zone Firewall Events | - | **~3 days** | Zone Traffic, Load Balancing Requests, Health Check Events | - | **~1 week** | DNS Analytics, Access Logins, Turnstile Challenges | - | **8 days** | Zone Traffic Breakdown | - | **~30-32 days** | the Gateway streams, KV, D1, R2, Queues, Workers AI, Durable Objects, Vectorize, Hyperdrive, Cache Reserve, Email Routing, DMARC, Images, AI Gateway, AutoRAG, Containers, Pipelines, Realtime, Browser Rendering, Stream | - | **~93 days** | Web Analytics Page Loads, Core Web Vitals | - | **~179 days** | Audit Logs | - - Every one of these was measured against the live API by widening the range until Cloudflare rejected it - none is documented. Caps may differ on other plans, and a few sit so close to a boundary that the next-widest option had to be dropped. - - Longer ranges are not offered because Cloudflare rejects them outright. Caps may differ on Free, Business and Enterprise plans. - -- **Daily-granularity datasets have no intraday view.** KV, D1 and Access analytics are aggregated by day, so their shortest timeframe is Last 7 days. +- **Analytics timeframes are capped per dataset and per plan.** Cloudflare's GraphQL Analytics API limits both how wide a single query can be and how far back it can reach, and the limits differ for every dataset. Each stream offers the timeframes its dataset allows. These limits were read from Cloudflare's own `settings` API for a Pro and a Free zone and confirmed by querying each stream at every offered timeframe: + + | Widest query / history kept | Data streams | Longest timeframe offered | + | --------------------------- | ------------ | ------------------------- | + | **1 day / 3 days** on Pro; none on Free | Zone Firewall Events | Last 24 hours (Last 7 and 30 days on higher plans - see below) | + | **3 days / 3 days** | Health Check Events, Load Balancing Requests | Last 24 hours | + | **7 days** | Access Logins, Turnstile Challenges, Network Error Logs, Page Shield Reports | Last 7 days | + | **30-31 days / 31 days** | Gateway HTTP Requests and Network Sessions, Stream Playback Quality, DNS Analytics, Zone Traffic Breakdown | Last 30 days | + | **31-32 days / 31-32 days** | Gateway DNS Queries, Email Routing, DMARC Reports, Images Requests, AI Gateway Cache and Errors, AutoRAG, Browser Rendering, Container Metrics, Hyperdrive, Queue Consumer Metrics, Realtime Usage, Vectorize, Workers AI | This month | + | **32-62 days / 62-92 days** | Worker Invocations, Pages Functions, KV, D1, R2, Durable Objects, Queue Backlog and Message Operations, Pipeline Ingestion, Cache Reserve, AI Gateway Requests, DNS Firewall Analytics, Stream Minutes Viewed | Last month | + | **61 days, daily only** | Images Unique Transformations | This month | + | **93 days / 184 days** | Web Analytics Page Loads, Core Web Vitals | This quarter | + | **180 days / 540 days** | Audit Logs | Last quarter | + | **365 days, daily** | Zone Traffic (hourly up to two days, then daily) | This year | + + *This month*, *This quarter* and *This year* end in the future; Cloudflare counts only the part that has elapsed, so they fit a cap the full period would not. Where a cap is exactly as wide as a timeframe - a 7-day cap and Last 7 days - the query starts one minute late, because Cloudflare measures the range up to the moment it receives the query and would otherwise reject it by the request's latency. + + Limits can be wider on Business and Enterprise plans. **Zone Firewall Events** is the one stream that offers timeframes a Pro plan cannot serve (Last 7 days and Last 30 days); on a plan whose limit is shorter, the tile shows an error naming the plan's limit rather than empty data. To see the limits for your own account, run this in the **GraphQL Query** stream with the **None** timeframe, a `zoneTag` in **Variables**, and **Path to rows** set to `data.viewer.zones`: + + ```graphql + query ($zoneTag: string!) { + viewer { + zones(filter: { zoneTag: $zoneTag }) { + settings { + firewallEventsAdaptiveGroups { maxDuration notOlderThan } + } + } + } + } + ``` + + `maxDuration` and `notOlderThan` are in seconds; swap in any other dataset name, or query `accounts(filter: { accountTag: $accountTag })` for account-level datasets. + +- **Time buckets follow the timeframe.** Time-series streams return one row per minute for Last hour, per 5 minutes up to 12 hours, per 15 minutes up to a day, hourly up to a week, then six-hourly or hourly up to a month (daily for R2 Operations) and daily beyond. Streams grouped by a dimension you choose, which can have many values, use coarser buckets to stay inside Cloudflare's row cap: 5 minutes for Last hour, 15 minutes up to 12 hours, hourly up to a day and daily beyond. A tile can aggregate these into coarser buckets but never finer ones. - **R2 must be activated before it returns anything.** If R2 has never been enabled in the Cloudflare dashboard, the import step for R2 buckets fails with *"Please enable R2 through the Cloudflare Dashboard"*. The step is optional, so the rest of the import still succeeds - but no R2 objects or metrics appear. - **Zero Trust Access must be enabled** for the Access application import to work; otherwise Cloudflare returns *"Access is not enabled"*. - **Web Analytics must be enabled per zone.** The RUM datasets are account-scoped and filtered to a zone by hostname, so a zone without the Web Analytics beacon installed returns nothing even though the query succeeds. Traffic from hosts that are not Cloudflare zones is not reachable from a zone-scoped tile. @@ -219,9 +236,9 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w - **Pages endpoints cap page size at 10.** Cloudflare rejects any larger `per_page` on the Pages API, so Pages projects and deployments are fetched ten at a time. - **Some resource lists are not paged.** R2 buckets, D1 databases, Queues, load balancer pools, Access applications, Vectorize indexes, Hyperdrive configs, Worker scripts and Worker routes are imported in a single request each. Where Cloudflare's paging behaviour could be proven against real data it is used (zones, accounts, DNS records, Pages projects, KV namespaces, Tunnels and Durable Object namespaces all page); the rest were left unpaged because the endpoint either ignores the paging parameters outright — as `workers/scripts` does — or holds too few records in the tested account to confirm they are honoured. If an account holds more of one of these than Cloudflare returns on a single page, the remainder is not imported. - **Rate limits.** The REST API allowed 1,200 requests per 300 seconds on the token tested, and Cloudflare documents a separate limit of 300 GraphQL queries per 5 minutes. Every analytics stream issues one request per selected object, so very large estates can hit these limits. -- **Long timeframes on per-minute analytics can return a partial series.** Cloudflare caps a GraphQL result at 10,000 rows, and the streams that break down by `datetime` produce one row per minute per dimension value - Worker Invocations, Pages Functions Invocations, Durable Object Invocations and Subrequests, D1 Queries, Queue Backlog and Consumer Metrics, R2 Operations and Storage, Cache Reserve Storage, Gateway HTTP Requests, Container Metrics, Pipeline Ingestion, Browser Rendering, Realtime Usage and Audit Logs. A busy resource can exceed 10,000 rows well inside `last30days`; because the queries order by time ascending, the excess is dropped from the end and the tile shows the earliest part of the range as though the series simply stopped. Prefer a narrower timeframe when a chart appears to end early. +- **A breakdown with very many values is truncated.** Cloudflare caps a GraphQL result at 10,000 rows (5,000 on some streams here). The time buckets above keep time-series streams well inside it, but a breakdown such as DNS Analytics by query name on a busy zone can still exceed it. Those streams order by count, so the rows dropped are the least frequent values rather than the most recent part of the range. -- **Hand-written GraphQL queries are unbounded.** The **GraphQL Query** stream runs whatever you give it, so it can hit limits the built-in streams are tuned to avoid: a large `limit` on a multi-dimension dataset can exceed the ~6 MB response cap, and a timeframe wider than that dataset's own cap fails outright. Prefer the pre-aggregated `*Groups` datasets over raw event datasets, and keep `limit` modest. The stream does not page, so your `limit` is the ceiling. +- **Hand-written GraphQL queries are unbounded.** The **GraphQL Query** stream runs whatever you give it, so it can hit limits the built-in streams are tuned to avoid: a large `limit` on a multi-dimension dataset can exceed the ~6 MB response cap, and a timeframe wider than that dataset's own cap fails with Cloudflare's error naming the limit. Prefer the pre-aggregated `*Groups` datasets over raw event datasets, and keep `limit` modest. The stream does not page, so your `limit` is the ceiling. - **Some analytics are only available on paid plans.** Page Shield and Network Error Logs return an authorization error on plans without them; Cache Reserve, Load Balancing and Health Checks are add-ons. An unentitled feature shows no data rather than an error in most tiles. - **A failed Cloudflare query can look like "no data".** Cloudflare answers a failed GraphQL query with HTTP 200 and an `errors` array, which the platform does not treat as a failure. Streams that use a post-request script raise these errors explicitly, but the simpler declarative streams will show an empty tile instead of an error message. - **Costs are unitless.** Cloudflare's AI Gateway analytics reports cost without stating a currency, so the plugin shows a plain number rather than assuming one. From 4ec766695b245b348eeb43fef34c85a2304b1dd4 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Nov 2026 22:26:57 +0000 Subject: [PATCH 15/27] Offer 30-day Turnstile analytics for Enterprise plans Cloudflare documents Turnstile's analytics lookback as 7 days on Free and 30 on Enterprise. Offer Last 30 days and, where the plan rejects it, raise an error naming the plan's limit instead of the raw quota message. Start the query a minute late so a 30-day window fits a 30-day cap. The README now cites Cloudflare's published per-plan limits and explains why the Security Events limits do not apply to Zone Firewall Events. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01FsDuPXY2CFtKbw4Cxn6cRF --- .../dataStreams/scripts/turnstileChallenges.js | 16 ++++++++++++++++ .../v2/dataStreams/turnstileChallenges.json | 4 ++-- plugins/Cloudflare/v2/docs/README.md | 10 ++++++++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/turnstileChallenges.js b/plugins/Cloudflare/v2/dataStreams/scripts/turnstileChallenges.js index b95030d8..194daf06 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/turnstileChallenges.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/turnstileChallenges.js @@ -10,6 +10,22 @@ // real error instead of silently shaping to zero rows. const graphqlErrors = (data && data.errors) || []; if (graphqlErrors.length) { + // Turnstile analytics look back 7 days on the Free plan and 30 on Enterprise, so the + // stream offers Last 30 days. Name the plan limit when it rejects one. String methods + // rather than a regex: backslash escapes do not survive into the deployed script. + const message = (graphqlErrors[0] && graphqlErrors[0].message) || ""; + const marker = "cannot request a time range wider than"; + const at = message.indexOf(marker); + if (at >= 0) { + const limit = message.slice(at + marker.length).trim().split(" ")[0].split(",")[0]; + throw new Error( + "Cloudflare's Turnstile plan for this account limits analytics to a range of " + + limit + + ". Choose a shorter timeframe - Enterprise Turnstile allows up to 30 days. (" + + message + + ")" + ); + } throw new Error( "Cloudflare GraphQL error: " + graphqlErrors.map((e) => (e && e.message) || JSON.stringify(e)).join(" | ") diff --git a/plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json b/plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json index 7e0fbaf6..781458d6 100644 --- a/plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json +++ b/plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json @@ -12,7 +12,7 @@ "variables": { "accountTag": "{{object.accountId}}", "siteKey": "{{object.rawId}}", - "start": "{{timeframe.start}}", + "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", "end": "{{timeframe.end}}" } }, @@ -59,5 +59,5 @@ "role": "value" } ], - "timeframes": ["last1hour", "last12hours", "last24hours", "last7days"] + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days"] } diff --git a/plugins/Cloudflare/v2/docs/README.md b/plugins/Cloudflare/v2/docs/README.md index d41fdd33..5937114c 100644 --- a/plugins/Cloudflare/v2/docs/README.md +++ b/plugins/Cloudflare/v2/docs/README.md @@ -199,7 +199,8 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w | --------------------------- | ------------ | ------------------------- | | **1 day / 3 days** on Pro; none on Free | Zone Firewall Events | Last 24 hours (Last 7 and 30 days on higher plans - see below) | | **3 days / 3 days** | Health Check Events, Load Balancing Requests | Last 24 hours | - | **7 days** | Access Logins, Turnstile Challenges, Network Error Logs, Page Shield Reports | Last 7 days | + | **7 days** | Access Logins, Network Error Logs, Page Shield Reports | Last 7 days | + | **7 days** on Free; **30 days** on Enterprise | Turnstile Challenges | Last 7 days (Last 30 days on Enterprise Turnstile) | | **30-31 days / 31 days** | Gateway HTTP Requests and Network Sessions, Stream Playback Quality, DNS Analytics, Zone Traffic Breakdown | Last 30 days | | **31-32 days / 31-32 days** | Gateway DNS Queries, Email Routing, DMARC Reports, Images Requests, AI Gateway Cache and Errors, AutoRAG, Browser Rendering, Container Metrics, Hyperdrive, Queue Consumer Metrics, Realtime Usage, Vectorize, Workers AI | This month | | **32-62 days / 62-92 days** | Worker Invocations, Pages Functions, KV, D1, R2, Durable Objects, Queue Backlog and Message Operations, Pipeline Ingestion, Cache Reserve, AI Gateway Requests, DNS Firewall Analytics, Stream Minutes Viewed | Last month | @@ -210,7 +211,12 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w *This month*, *This quarter* and *This year* end in the future; Cloudflare counts only the part that has elapsed, so they fit a cap the full period would not. Where a cap is exactly as wide as a timeframe - a 7-day cap and Last 7 days - the query starts one minute late, because Cloudflare measures the range up to the moment it receives the query and would otherwise reject it by the request's latency. - Limits can be wider on Business and Enterprise plans. **Zone Firewall Events** is the one stream that offers timeframes a Pro plan cannot serve (Last 7 days and Last 30 days); on a plan whose limit is shorter, the tile shows an error naming the plan's limit rather than empty data. To see the limits for your own account, run this in the **GraphQL Query** stream with the **None** timeframe, a `zoneTag` in **Variables**, and **Path to rows** set to `data.viewer.zones`: + Limits can be wider on Business and Enterprise plans. Two streams offer timeframes that only higher plans can serve, and on a plan whose limit is shorter the tile shows an error naming that limit rather than empty data: + + - **Zone Firewall Events** offers Last 7 days and Last 30 days. Its grouped dataset, `firewallEventsAdaptiveGroups`, allows 1 day on Pro and is not available on Free. Cloudflare publishes 30-31 day limits for Security Events, but [those apply to the raw event dataset](https://developers.cloudflare.com/waf/analytics/security-events/#limits), which returns individual events rather than counts. + - **Turnstile Challenges** offers Last 30 days, which [Cloudflare documents](https://developers.cloudflare.com/turnstile/plans/) as the Enterprise lookback; Free is limited to 7 days. + + To see the limits for your own account, run this in the **GraphQL Query** stream with the **None** timeframe, a `zoneTag` in **Variables**, and **Path to rows** set to `data.viewer.zones`: ```graphql query ($zoneTag: string!) { From 60e15c7210ae1bd039143ba5cc95e7e6ed816dc5 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Nov 2026 22:36:44 +0000 Subject: [PATCH 16/27] Add Zone Firewall Event Volume for 30-day firewall trends on every plan Zone Firewall Events groups by action and rule from firewallEventsAdaptiveGroups, which allows 1 day on Pro and is unavailable on Free. firewallEventsAdaptiveByTimeGroups counts every firewall event for up to 30 days on every plan, but can only filter by action and service, not group by them - so it gets its own stream rather than replacing the first. The raw firewallEventsAdaptive dataset was rejected: it returns individual events newest first, capped at 10,000 rows, which on a zone logging ~78,000 events a day covered only the last 36 hours of a 30-day window. The Zone dashboard gains a 30-day event volume line graph above the firewall breakdowns. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01FsDuPXY2CFtKbw4Cxn6cRF --- .../scripts/zoneFirewallEventVolume.js | 36 ++++++ .../dataStreams/zoneFirewallEventVolume.json | 101 +++++++++++++++ .../v2/defaultContent/Core/zone.dash.json | 120 +++++++++++++----- plugins/Cloudflare/v2/docs/README.md | 4 +- 4 files changed, 228 insertions(+), 33 deletions(-) create mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/zoneFirewallEventVolume.js create mode 100644 plugins/Cloudflare/v2/dataStreams/zoneFirewallEventVolume.json diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/zoneFirewallEventVolume.js b/plugins/Cloudflare/v2/dataStreams/scripts/zoneFirewallEventVolume.js new file mode 100644 index 00000000..f0a83297 --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/scripts/zoneFirewallEventVolume.js @@ -0,0 +1,36 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a +// postRequestScript bypasses the stream's declarative errorHandling entirely, +// so the error is raised here or it would be swallowed into an empty result. +if (data && data.errors && data.errors.length) { + throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); +} + +// dataStreams/scripts/zoneFirewallEventVolume.js +// firewallEventsAdaptiveByTimeGroups counts every firewall event and allows 30 days on +// every plan, unlike firewallEventsAdaptiveGroups behind Zone Firewall Events (1 day on +// Pro, unavailable on Free). It cannot group by action or service, only filter by them, +// so this stream is a single series over time. The query aliases the time bucket it +// chose for the timeframe to `datetime`. +// +// SquaredUp runs this stream once per zone in scope and joins the rows, so stamp the +// zone onto every row to let multi-zone tiles tell them apart. + +const zone = (context.objects && context.objects[0]) || {}; +const zoneTag = zone.rawId || ""; +const zoneName = zone.name || zoneTag; + +const groups = + (data && + data.data && + data.data.viewer && + data.data.viewer.zones && + data.data.viewer.zones[0] && + data.data.viewer.zones[0].firewallEventsAdaptiveByTimeGroups) || + []; + +result = groups.map((row) => ({ + datetime: row.dimensions && row.dimensions.datetime, + events: Number(row.count || 0) || 0, + zoneName: zoneName, + zoneTag: zoneTag, +})); diff --git a/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventVolume.json b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventVolume.json new file mode 100644 index 00000000..609f7ca5 --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventVolume.json @@ -0,0 +1,101 @@ +{ + "name": "zoneFirewallEventVolume", + "displayName": "Zone Firewall Event Volume", + "description": "Firewall event counts over time for a zone, optionally filtered by action and service (up to 30 days on every plan)", + "tags": ["Zone", "Security"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($zoneTag:string!,$filter:ZoneFirewallEventsAdaptiveByTimeGroupsFilter_InputObject){viewer{zones(filter:{zoneTag:$zoneTag}){firewallEventsAdaptiveByTimeGroups(limit:10000,filter:$filter,orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", + "variables": { + "zoneTag": "{{object.rawId}}", + "filter": "{{ Object.assign({ datetime_geq: new Date((timeframe.unixStart + 60) * 1000).toISOString(), datetime_leq: timeframe.end }, (typeof actions !== 'undefined' && actions ? [].concat(typeof actions === 'string' && actions.trim().charAt(0) === '[' ? JSON.parse(actions) : actions).map((v) => (v && v.value !== undefined ? v.value : v)).filter((v) => v) : []).length ? { action_in: (typeof actions !== 'undefined' && actions ? [].concat(typeof actions === 'string' && actions.trim().charAt(0) === '[' ? JSON.parse(actions) : actions).map((v) => (v && v.value !== undefined ? v.value : v)).filter((v) => v) : []) } : {}, (typeof sources !== 'undefined' && sources ? [].concat(typeof sources === 'string' && sources.trim().charAt(0) === '[' ? JSON.parse(sources) : sources).map((v) => (v && v.value !== undefined ? v.value : v)).filter((v) => v) : []).length ? { source_in: (typeof sources !== 'undefined' && sources ? [].concat(typeof sources === 'string' && sources.trim().charAt(0) === '[' ? JSON.parse(sources) : sources).map((v) => (v && v.value !== undefined ? v.value : v)).filter((v) => v) : []) } : {}) }}" + } + }, + "postRequestScript": "zoneFirewallEventVolume.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": ["Cloudflare Zone"] + } + }, + "ui": [ + { + "type": "autocomplete", + "name": "actions", + "label": "Action(s)", + "isMulti": true, + "isClearable": true, + "allowCustomValues": true, + "data": { + "source": "fixed", + "values": [ + { "value": "block", "label": "Block" }, + { "value": "managed_challenge", "label": "Managed challenge" }, + { "value": "challenge", "label": "Interactive challenge" }, + { "value": "jschallenge", "label": "JS challenge" }, + { "value": "log", "label": "Log" }, + { "value": "skip", "label": "Skip" }, + { "value": "allow", "label": "Allow" } + ] + } + }, + { + "type": "autocomplete", + "name": "sources", + "label": "Service(s)", + "isMulti": true, + "isClearable": true, + "allowCustomValues": true, + "data": { + "source": "fixed", + "values": [ + { "value": "firewallManaged", "label": "Managed rules" }, + { "value": "firewallCustom", "label": "Custom rules" }, + { "value": "rateLimit", "label": "Rate limiting rules" }, + { "value": "bic", "label": "Browser Integrity Check" }, + { "value": "securityLevel", "label": "Security level" }, + { "value": "ip", "label": "IP Access rules" }, + { "value": "uaBlock", "label": "User Agent Blocking" }, + { "value": "zoneLockdown", "label": "Zone Lockdown" }, + { "value": "botFight", "label": "Bot Fight Mode" } + ] + } + } + ], + "metadata": [ + { + "name": "datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "events", + "displayName": "Events", + "shape": "number", + "role": "value" + }, + { + "name": "zoneName", + "displayName": "Zone", + "shape": "string", + "role": "label" + }, + { + "name": "zoneTag", + "displayName": "Zone Tag", + "shape": "string", + "visible": false + } + ], + "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days"] +} diff --git a/plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json b/plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json index abc908d6..f32c0b74 100644 --- a/plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json @@ -670,9 +670,65 @@ } }, { - "i": "b5b428c0-6e8b-4b20-8637-826523d8875e", + "i": "414ccb22-cce5-4121-ba54-ba0c4ae80aa8", "x": 0, "y": 14, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Firewall Events (Last 30 Days)", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneFirewallEventVolume]}}", + "name": "zoneFirewallEventVolume", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "timeframe": "last30days", + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "datetime", + "yAxisColumn": [ + "events" + ], + "seriesColumn": "zoneName", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "b5b428c0-6e8b-4b20-8637-826523d8875e", + "x": 0, + "y": 17, "w": 2, "h": 3, "moved": false, @@ -758,7 +814,7 @@ { "i": "f70d4a4d-aa25-436e-bc2d-f57913923742", "x": 2, - "y": 14, + "y": 17, "w": 2, "h": 3, "moved": false, @@ -829,7 +885,7 @@ { "i": "ab07298c-beb2-45ad-ab55-973b5ee13c9e", "x": 0, - "y": 17, + "y": 20, "w": 2, "h": 3, "moved": false, @@ -915,7 +971,7 @@ { "i": "36980a5b-9966-4da8-b4ae-03a64c40c648", "x": 2, - "y": 17, + "y": 20, "w": 2, "h": 3, "moved": false, @@ -986,7 +1042,7 @@ { "i": "6084f30d-d547-4fdf-8712-6ac71b5fb03a", "x": 0, - "y": 20, + "y": 23, "w": 2, "h": 4, "moved": false, @@ -1047,7 +1103,7 @@ { "i": "b32501ab-3b1e-47da-bb9c-19fab121891f", "x": 2, - "y": 20, + "y": 23, "w": 2, "h": 4, "moved": false, @@ -1113,7 +1169,7 @@ { "i": "2a5caeac-bbae-4322-934c-4a58f34091f0", "x": 0, - "y": 24, + "y": 27, "w": 4, "h": 4, "moved": false, @@ -1175,7 +1231,7 @@ { "i": "4340f0d4-7cb2-495e-a086-4b115ac7eede", "x": 0, - "y": 28, + "y": 31, "w": 2, "h": 3, "moved": false, @@ -1258,7 +1314,7 @@ { "i": "d0c74ae9-3aca-4708-a4a1-373db8a88696", "x": 2, - "y": 28, + "y": 31, "w": 2, "h": 3, "moved": false, @@ -1341,7 +1397,7 @@ { "i": "99e46b39-b7fd-4d39-8990-7bfec62f4a92", "x": 0, - "y": 31, + "y": 34, "w": 1, "h": 2, "moved": false, @@ -1394,7 +1450,7 @@ { "i": "5817c6a0-7759-4c3a-93a8-dfce7f44fc97", "x": 1, - "y": 31, + "y": 34, "w": 1, "h": 2, "moved": false, @@ -1447,7 +1503,7 @@ { "i": "3681fbe9-0fb2-449b-85c3-f66e81c37fe3", "x": 2, - "y": 31, + "y": 34, "w": 1, "h": 2, "moved": false, @@ -1500,7 +1556,7 @@ { "i": "865ade66-66ea-441f-a6d0-27a3d8a7f26d", "x": 3, - "y": 31, + "y": 34, "w": 1, "h": 2, "moved": false, @@ -1553,7 +1609,7 @@ { "i": "0f48a7c9-fcf3-416a-b2f0-d6c2e5cabcc1", "x": 0, - "y": 33, + "y": 36, "w": 2, "h": 3, "moved": false, @@ -1632,7 +1688,7 @@ { "i": "1448aa66-c33d-42c8-b310-aab9100ef8a2", "x": 2, - "y": 33, + "y": 36, "w": 2, "h": 3, "moved": false, @@ -1704,7 +1760,7 @@ { "i": "3fa5456b-67bc-4f54-b2f7-9f20cad1aa50", "x": 0, - "y": 36, + "y": 39, "w": 2, "h": 3, "moved": false, @@ -1791,7 +1847,7 @@ { "i": "b46fbd5f-b49c-40e6-9780-39fd9d287f6c", "x": 2, - "y": 36, + "y": 39, "w": 2, "h": 3, "moved": false, @@ -1864,7 +1920,7 @@ { "i": "736448a6-7b52-440a-b866-f2f4b23ab048", "x": 0, - "y": 39, + "y": 42, "w": 4, "h": 3, "moved": false, @@ -1946,7 +2002,7 @@ { "i": "bba8874b-de16-4088-ba86-f7a3f1242e6e", "x": 0, - "y": 42, + "y": 45, "w": 2, "h": 3, "moved": false, @@ -2033,7 +2089,7 @@ { "i": "c8c8b28e-1fed-4543-87d6-821ef74a884b", "x": 2, - "y": 42, + "y": 45, "w": 2, "h": 3, "moved": false, @@ -2106,7 +2162,7 @@ { "i": "bb2d2cdd-d041-435a-b77f-47ef0f8190b8", "x": 0, - "y": 45, + "y": 48, "w": 2, "h": 3, "moved": false, @@ -2181,7 +2237,7 @@ { "i": "78551a25-ceca-4256-9111-1e195d3afa3b", "x": 2, - "y": 45, + "y": 48, "w": 2, "h": 3, "moved": false, @@ -2256,7 +2312,7 @@ { "i": "5a35c781-2682-4880-bff7-77c61d52ae5f", "x": 0, - "y": 48, + "y": 51, "w": 2, "h": 3, "moved": false, @@ -2328,7 +2384,7 @@ { "i": "e7ec1705-838a-4d37-918b-496b4da2e138", "x": 2, - "y": 48, + "y": 51, "w": 2, "h": 3, "moved": false, @@ -2403,7 +2459,7 @@ { "i": "404f3e25-56a7-4f0d-b112-e9c12846d0bb", "x": 0, - "y": 51, + "y": 54, "w": 2, "h": 3, "moved": false, @@ -2475,7 +2531,7 @@ { "i": "f741cb88-09ec-49d5-afac-2e55358ec1c9", "x": 2, - "y": 51, + "y": 54, "w": 2, "h": 3, "moved": false, @@ -2562,7 +2618,7 @@ { "i": "d2d06e16-5181-4c42-9faf-f5eb6986072f", "x": 0, - "y": 54, + "y": 57, "w": 2, "h": 3, "moved": false, @@ -2633,7 +2689,7 @@ { "i": "2072f98c-365b-4001-9594-eed5b5612479", "x": 2, - "y": 54, + "y": 57, "w": 2, "h": 3, "moved": false, @@ -2704,7 +2760,7 @@ { "i": "d1d83606-df02-4ee0-88ad-4b88401340ad", "x": 0, - "y": 57, + "y": 60, "w": 2, "h": 3, "moved": false, @@ -2773,7 +2829,7 @@ { "i": "18a14576-aa42-440d-8f32-28024ebb0003", "x": 2, - "y": 57, + "y": 60, "w": 2, "h": 3, "moved": false, @@ -2845,7 +2901,7 @@ { "i": "0b37e21b-6c6a-4442-8a58-507f77fb6451", "x": 0, - "y": 60, + "y": 63, "w": 2, "h": 3, "moved": false, @@ -2932,7 +2988,7 @@ { "i": "60c857c2-28a9-47cf-b0aa-85676a291c9f", "x": 2, - "y": 60, + "y": 63, "w": 2, "h": 3, "moved": false, diff --git a/plugins/Cloudflare/v2/docs/README.md b/plugins/Cloudflare/v2/docs/README.md index 5937114c..e9db9fd9 100644 --- a/plugins/Cloudflare/v2/docs/README.md +++ b/plugins/Cloudflare/v2/docs/README.md @@ -69,6 +69,7 @@ The out-of-the-box dashboards open with a **Cloudflare Overview**, with perspect - **Zone Traffic** - requests, bandwidth, cached traffic, threats, page views and cache hit ratio for a zone, hourly for timeframes up to two days and daily beyond. - **Zone Traffic Breakdown** - requests, bytes and visits for a zone grouped by a dimension you choose (country, status code, cache status, host, device type, HTTP protocol or content type). - **Zone Firewall Events** - firewall and WAF event counts for a zone by action, grouped by rule, service, country, host, user agent or path. +- **Zone Firewall Event Volume** - firewall and WAF event counts over time for a zone, optionally filtered by action and service, for up to 30 days on every plan. - **Load Balancing Requests** - load balancer request counts for a zone by load balancer, pool, origin and edge location. - **DNS Records** - every DNS record in a zone with type, content, TTL, proxy status and tags. - **SSL Certificates** - certificate packs for a zone with issuer, validation method, expiry date and days until expiry. @@ -198,6 +199,7 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w | Widest query / history kept | Data streams | Longest timeframe offered | | --------------------------- | ------------ | ------------------------- | | **1 day / 3 days** on Pro; none on Free | Zone Firewall Events | Last 24 hours (Last 7 and 30 days on higher plans - see below) | + | **30 days / 31 days** on every plan | Zone Firewall Event Volume | Last 30 days | | **3 days / 3 days** | Health Check Events, Load Balancing Requests | Last 24 hours | | **7 days** | Access Logins, Network Error Logs, Page Shield Reports | Last 7 days | | **7 days** on Free; **30 days** on Enterprise | Turnstile Challenges | Last 7 days (Last 30 days on Enterprise Turnstile) | @@ -213,7 +215,7 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w Limits can be wider on Business and Enterprise plans. Two streams offer timeframes that only higher plans can serve, and on a plan whose limit is shorter the tile shows an error naming that limit rather than empty data: - - **Zone Firewall Events** offers Last 7 days and Last 30 days. Its grouped dataset, `firewallEventsAdaptiveGroups`, allows 1 day on Pro and is not available on Free. Cloudflare publishes 30-31 day limits for Security Events, but [those apply to the raw event dataset](https://developers.cloudflare.com/waf/analytics/security-events/#limits), which returns individual events rather than counts. + - **Zone Firewall Events** offers Last 7 days and Last 30 days. Its grouped dataset, `firewallEventsAdaptiveGroups`, allows 1 day on Pro and is not available on Free. Cloudflare publishes 30-31 day limits for Security Events, but [those apply to the raw event dataset](https://developers.cloudflare.com/waf/analytics/security-events/#limits), which returns individual events rather than counts. Use **Zone Firewall Event Volume** for longer ranges: its dataset counts every event for up to 30 days on every plan, including Free, but can only filter by action and service rather than break down by them. - **Turnstile Challenges** offers Last 30 days, which [Cloudflare documents](https://developers.cloudflare.com/turnstile/plans/) as the Enterprise lookback; Free is limited to 7 days. To see the limits for your own account, run this in the **GraphQL Query** stream with the **None** timeframe, a `zoneTag` in **Variables**, and **Path to rows** set to `data.viewer.zones`: From e70c1423199cfb17ac4f0b3f0fccd0b7afbf42b4 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Nov 2026 23:27:57 +0000 Subject: [PATCH 17/27] Add account traffic and Workers, storage and RUM metric streams - Opt every single-scope GraphQL stream into Cloudflare's account-based rate limiting (X-Rate-Limit-Type: account-based), so each account and zone gets its own query budget instead of sharing one per token. GraphQL Query is left out: the model does not support viewer-level zone lists. - Replace pathToData on the 30 declarative GraphQL streams with a shared graphqlRows.js that raises Cloudflare's HTTP 200 errors through api.report.error and flattens rows exactly as expandInnerObjects did. Columns were compared before and after on every stream with data. - Add Account Traffic: one query across every zone in an account, grouped by zone (resolved to the imported zone's name) or another dimension. The Overview and Account dashboards gain traffic tiles. - Add Worker Subrequests, Cron Trigger Runs, Static Asset Requests, Cache Requests and Smart Placement; Workers Build Minutes; R2 Bandwidth; Queue Delayed Backlog; Hyperdrive Connection Pool; Durable Object Activity; and Web Analytics Page Load Timing, each with tiles on its dashboard. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01FsDuPXY2CFtKbw4Cxn6cRF --- .../v2/dataStreams/accessLogins.json | 4 +- .../v2/dataStreams/accountTraffic.json | 133 ++++++ .../v2/dataStreams/aiGatewayCache.json | 4 +- .../v2/dataStreams/aiGatewayErrors.json | 4 +- .../v2/dataStreams/aiGatewayRequests.json | 4 +- .../Cloudflare/v2/dataStreams/auditLogs.json | 1 + .../v2/dataStreams/autoragQueries.json | 4 +- .../v2/dataStreams/browserRendering.json | 1 + .../dataStreams/cacheReserveOperations.json | 1 + .../v2/dataStreams/cacheReserveStorage.json | 4 +- .../v2/dataStreams/containerMetrics.json | 1 + .../v2/dataStreams/d1Analytics.json | 4 +- .../Cloudflare/v2/dataStreams/d1Queries.json | 4 +- .../Cloudflare/v2/dataStreams/d1Storage.json | 4 +- .../v2/dataStreams/dmarcReports.json | 1 + .../v2/dataStreams/dnsFirewallAnalytics.json | 1 + .../v2/dataStreams/durableObjectActivity.json | 136 ++++++ .../dataStreams/durableObjectInvocations.json | 4 +- .../v2/dataStreams/durableObjectStorage.json | 4 +- .../dataStreams/durableObjectSubrequests.json | 4 +- .../v2/dataStreams/emailRouting.json | 1 + .../v2/dataStreams/gatewayDnsQueries.json | 1 + .../v2/dataStreams/gatewayHttpRequests.json | 1 + .../dataStreams/gatewayNetworkSessions.json | 1 + .../v2/dataStreams/hyperdrivePoolSizes.json | 88 ++++ .../v2/dataStreams/hyperdriveQueries.json | 4 +- .../v2/dataStreams/imagesRequests.json | 1 + .../v2/dataStreams/imagesTransformations.json | 1 + .../v2/dataStreams/kvOperations.json | 4 +- .../Cloudflare/v2/dataStreams/kvStorage.json | 4 +- .../pagesFunctionsInvocations.json | 4 +- .../v2/dataStreams/pipelineIngestion.json | 4 +- .../v2/dataStreams/queueBacklog.json | 4 +- .../v2/dataStreams/queueConsumerMetrics.json | 4 +- .../v2/dataStreams/queueDelayedBacklog.json | 67 +++ .../dataStreams/queueMessageOperations.json | 4 +- .../v2/dataStreams/r2Bandwidth.json | 70 ++++ .../v2/dataStreams/r2Operations.json | 4 +- .../Cloudflare/v2/dataStreams/r2Storage.json | 4 +- .../v2/dataStreams/realtimeUsage.json | 4 +- .../v2/dataStreams/rumPageLoadTiming.json | 150 +++++++ .../v2/dataStreams/rumPageLoads.json | 1 + .../v2/dataStreams/rumWebVitals.json | 4 +- .../v2/dataStreams/scripts/accountTraffic.js | 34 ++ .../v2/dataStreams/scripts/graphqlRows.js | 55 +++ .../Cloudflare/v2/dataStreams/streamCmcd.json | 1 + .../v2/dataStreams/streamMinutesViewed.json | 4 +- .../v2/dataStreams/turnstileChallenges.json | 1 + .../v2/dataStreams/vectorizeQueries.json | 4 +- .../v2/dataStreams/vectorizeStorage.json | 4 +- .../v2/dataStreams/workerBuildMinutes.json | 63 +++ .../v2/dataStreams/workerCacheRequests.json | 72 ++++ .../v2/dataStreams/workerCronRuns.json | 110 +++++ .../v2/dataStreams/workerInvocations.json | 4 +- .../v2/dataStreams/workerSmartPlacement.json | 86 ++++ .../v2/dataStreams/workerStaticAssets.json | 94 +++++ .../v2/dataStreams/workerSubrequests.json | 135 ++++++ .../v2/dataStreams/workersAiInference.json | 1 + .../v2/dataStreams/zoneDnsAnalytics.json | 1 + .../dataStreams/zoneFirewallEventVolume.json | 1 + .../v2/dataStreams/zoneFirewallEvents.json | 1 + .../v2/dataStreams/zoneHealthCheckEvents.json | 4 +- .../v2/dataStreams/zoneLoadBalancing.json | 4 +- .../v2/dataStreams/zoneNelReports.json | 1 + .../v2/dataStreams/zonePageShield.json | 1 + .../v2/dataStreams/zoneTraffic.json | 1 + .../v2/dataStreams/zoneTrafficBreakdown.json | 1 + .../Compute/durableObjectNamespace.dash.json | 224 ++++++++++ .../v2/defaultContent/Compute/queue.dash.json | 55 +++ .../defaultContent/Compute/worker.dash.json | 386 ++++++++++++++++++ .../v2/defaultContent/Core/account.dash.json | 297 ++++++++++++++ .../v2/defaultContent/Core/zone.dash.json | 61 +++ .../hyperdriveConfig.dash.json | 112 +++++ .../Storage & Databases/r2Bucket.dash.json | 56 +++ .../v2/defaultContent/overview.dash.json | 257 ++++++++++-- plugins/Cloudflare/v2/docs/README.md | 27 +- 76 files changed, 2819 insertions(+), 92 deletions(-) create mode 100644 plugins/Cloudflare/v2/dataStreams/accountTraffic.json create mode 100644 plugins/Cloudflare/v2/dataStreams/durableObjectActivity.json create mode 100644 plugins/Cloudflare/v2/dataStreams/hyperdrivePoolSizes.json create mode 100644 plugins/Cloudflare/v2/dataStreams/queueDelayedBacklog.json create mode 100644 plugins/Cloudflare/v2/dataStreams/r2Bandwidth.json create mode 100644 plugins/Cloudflare/v2/dataStreams/rumPageLoadTiming.json create mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/accountTraffic.js create mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/graphqlRows.js create mode 100644 plugins/Cloudflare/v2/dataStreams/workerBuildMinutes.json create mode 100644 plugins/Cloudflare/v2/dataStreams/workerCacheRequests.json create mode 100644 plugins/Cloudflare/v2/dataStreams/workerCronRuns.json create mode 100644 plugins/Cloudflare/v2/dataStreams/workerSmartPlacement.json create mode 100644 plugins/Cloudflare/v2/dataStreams/workerStaticAssets.json create mode 100644 plugins/Cloudflare/v2/dataStreams/workerSubrequests.json diff --git a/plugins/Cloudflare/v2/dataStreams/accessLogins.json b/plugins/Cloudflare/v2/dataStreams/accessLogins.json index 4cf1c6c9..c7948608 100644 --- a/plugins/Cloudflare/v2/dataStreams/accessLogins.json +++ b/plugins/Cloudflare/v2/dataStreams/accessLogins.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$appId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){accessLoginRequestsAdaptiveGroups(limit:10000,filter:{appId:$appId,datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} identityProvider isSuccessfulLogin country hasWarpEnabled}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.accessLoginRequestsAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/accountTraffic.json b/plugins/Cloudflare/v2/dataStreams/accountTraffic.json new file mode 100644 index 00000000..b850b355 --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/accountTraffic.json @@ -0,0 +1,133 @@ +{ + "name": "accountTraffic", + "displayName": "Account Traffic", + "description": "HTTP requests, bandwidth and visits across every zone in an account, grouped by zone or another selectable dimension", + "tags": [ + "Analytics" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "headers": [ + { + "key": "X-Rate-Limit-Type", + "value": "account-based" + } + ], + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){httpRequestsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count sum{edgeResponseBytes visits} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown || 'zoneTag'}} }}}}}", + "variables": { + "accountTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "accountTraffic.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "zoneTag", + "options": [ + { + "value": "zoneTag", + "label": "Zone" + }, + { + "value": "clientCountryName", + "label": "Country" + }, + { + "value": "edgeResponseStatus", + "label": "Status code" + }, + { + "value": "cacheStatus", + "label": "Cache status" + }, + { + "value": "clientRequestHTTPHost", + "label": "Host" + }, + { + "value": "clientDeviceType", + "label": "Device type" + } + ] + } + ], + "metadata": [ + { + "name": "datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "zoneTag", + "displayName": "Zone Tag", + "shape": "string", + "visible": false + }, + { + "name": "zoneName", + "displayName": "Zone", + "sourceId": "zoneTag", + "sourceType": "Cloudflare Zone", + "objectPropertyPath": "name", + "shape": "string" + }, + { + "name": "requests", + "displayName": "Requests", + "shape": "number", + "role": "value" + }, + { + "name": "bytes", + "displayName": "Bandwidth", + "shape": "bytes" + }, + { + "name": "visits", + "displayName": "Visits", + "shape": "number" + }, + { + "name": "accountName", + "displayName": "Account", + "shape": "string" + } + ], + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth" + ] +} diff --git a/plugins/Cloudflare/v2/dataStreams/aiGatewayCache.json b/plugins/Cloudflare/v2/dataStreams/aiGatewayCache.json index 64d0c37a..6849ebae 100644 --- a/plugins/Cloudflare/v2/dataStreams/aiGatewayCache.json +++ b/plugins/Cloudflare/v2/dataStreams/aiGatewayCache.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$gateway:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiGatewayCacheAdaptiveGroups(limit:10000,filter:{gateway:$gateway,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} cacheOp}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.aiGatewayCacheAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/aiGatewayErrors.json b/plugins/Cloudflare/v2/dataStreams/aiGatewayErrors.json index 8eafa4ed..19bdd8ae 100644 --- a/plugins/Cloudflare/v2/dataStreams/aiGatewayErrors.json +++ b/plugins/Cloudflare/v2/dataStreams/aiGatewayErrors.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$gateway:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiGatewayErrorsAdaptiveGroups(limit:10000,filter:{gateway:$gateway,datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.aiGatewayErrorsAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/aiGatewayRequests.json b/plugins/Cloudflare/v2/dataStreams/aiGatewayRequests.json index e07c635a..c60e9461 100644 --- a/plugins/Cloudflare/v2/dataStreams/aiGatewayRequests.json +++ b/plugins/Cloudflare/v2/dataStreams/aiGatewayRequests.json @@ -10,6 +10,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$gateway:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiGatewayRequestsAdaptiveGroups(limit:10000,filter:{gateway:$gateway,datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}} sum{cost tokensIn tokensOut totalTokens cachedRequests erroredRequests} quantiles{durationMsP50 durationMsP95}}}}}", "variables": { @@ -19,8 +20,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.aiGatewayRequestsAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, diff --git a/plugins/Cloudflare/v2/dataStreams/auditLogs.json b/plugins/Cloudflare/v2/dataStreams/auditLogs.json index d9d297f5..ea886763 100644 --- a/plugins/Cloudflare/v2/dataStreams/auditLogs.json +++ b/plugins/Cloudflare/v2/dataStreams/auditLogs.json @@ -10,6 +10,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){auditLogsGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/autoragQueries.json b/plugins/Cloudflare/v2/dataStreams/autoragQueries.json index 7a9aa21b..1f6a373e 100644 --- a/plugins/Cloudflare/v2/dataStreams/autoragQueries.json +++ b/plugins/Cloudflare/v2/dataStreams/autoragQueries.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$instanceId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiSearchAPIAdaptiveGroups(limit:10000,filter:{instanceId:$instanceId,datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count sum{aiSearchCount searchCount} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.aiSearchAPIAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/browserRendering.json b/plugins/Cloudflare/v2/dataStreams/browserRendering.json index 5f27872a..2f6b1b8e 100644 --- a/plugins/Cloudflare/v2/dataStreams/browserRendering.json +++ b/plugins/Cloudflare/v2/dataStreams/browserRendering.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){browserRenderingEventsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count avg{avgConcurrentSessions} min{earliestBrowserStartTime} max{latestBrowserEndTime} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} sessionId {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json b/plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json index f426006f..19385ef5 100644 --- a/plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json +++ b/plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){cacheReserveOperationsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){sum{requests}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/cacheReserveStorage.json b/plugins/Cloudflare/v2/dataStreams/cacheReserveStorage.json index 106eb3aa..9f49f627 100644 --- a/plugins/Cloudflare/v2/dataStreams/cacheReserveStorage.json +++ b/plugins/Cloudflare/v2/dataStreams/cacheReserveStorage.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){cacheReserveStorageAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){max{objectCount storedBytes}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { @@ -15,8 +16,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.zones.0.cacheReserveStorageAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/containerMetrics.json b/plugins/Cloudflare/v2/dataStreams/containerMetrics.json index 1315eb59..441ceff8 100644 --- a/plugins/Cloudflare/v2/dataStreams/containerMetrics.json +++ b/plugins/Cloudflare/v2/dataStreams/containerMetrics.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$applicationId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){containersMetricsAdaptiveGroups(limit:10000,filter:{applicationId:$applicationId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){count avg{cpuUtilization memory containerUptime} sum{rxBytes txBytes} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/d1Analytics.json b/plugins/Cloudflare/v2/dataStreams/d1Analytics.json index 622915f0..fb59f2ed 100644 --- a/plugins/Cloudflare/v2/dataStreams/d1Analytics.json +++ b/plugins/Cloudflare/v2/dataStreams/d1Analytics.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$databaseId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){d1AnalyticsAdaptiveGroups(limit:10000,filter:{databaseId:$databaseId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{readQueries writeQueries rowsRead rowsWritten queryBatchResponseBytes}quantiles{queryBatchTimeMsP50 queryBatchTimeMsP90 queryBatchTimeMsP99}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.d1AnalyticsAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/d1Queries.json b/plugins/Cloudflare/v2/dataStreams/d1Queries.json index 594ce1ad..52137fd9 100644 --- a/plugins/Cloudflare/v2/dataStreams/d1Queries.json +++ b/plugins/Cloudflare/v2/dataStreams/d1Queries.json @@ -10,6 +10,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$databaseId:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){d1QueriesAdaptiveGroups(limit:10000,filter:{databaseId:$databaseId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){count sum{rowsRead rowsWritten rowsReturned}quantiles{queryDurationMsP50 queryDurationMsP95 queryDurationMsP99}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} databaseRole}}}}}", "variables": { @@ -19,8 +20,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.d1QueriesAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/d1Storage.json b/plugins/Cloudflare/v2/dataStreams/d1Storage.json index 1a957270..bcc13a18 100644 --- a/plugins/Cloudflare/v2/dataStreams/d1Storage.json +++ b/plugins/Cloudflare/v2/dataStreams/d1Storage.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$databaseId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){d1StorageAdaptiveGroups(limit:10000,filter:{databaseId:$databaseId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){max{databaseSizeBytes}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.d1StorageAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/dmarcReports.json b/plugins/Cloudflare/v2/dataStreams/dmarcReports.json index c108d4be..ef23c157 100644 --- a/plugins/Cloudflare/v2/dataStreams/dmarcReports.json +++ b/plugins/Cloudflare/v2/dataStreams/dmarcReports.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){dmarcReportsSourcesAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[sum_totalMatchingMessages_DESC]){sum{totalMatchingMessages dmarc} avg{dmarc} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json b/plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json index 9afa20fe..ae50ecb2 100644 --- a/plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json +++ b/plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){dnsFirewallAnalyticsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count quantiles{processingTimeUsP50} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/durableObjectActivity.json b/plugins/Cloudflare/v2/dataStreams/durableObjectActivity.json new file mode 100644 index 00000000..97b506d7 --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/durableObjectActivity.json @@ -0,0 +1,136 @@ +{ + "name": "durableObjectActivity", + "displayName": "Durable Object Activity", + "description": "Active time, CPU time, storage operations, errors and memory for a Durable Object namespace", + "tags": [ + "Compute", + "Analytics" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "headers": [ + { + "key": "X-Rate-Limit-Type", + "value": "account-based" + } + ], + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$namespaceId:string!){viewer{accounts(filter:{accountTag:$accountTag}){durableObjectsPeriodicGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{activeTime cpuTime rowsRead rowsWritten storageReadUnits storageWriteUnits subrequests exceededCpuErrors exceededMemoryErrors fatalInternalErrors} max{activeWebsocketConnections memoryUsageBytes} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} }}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "namespaceId": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "graphqlRows.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Durable Object Namespace" + ] + } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "sum.activeTime", + "displayName": "Active time (µs)", + "shape": "number", + "visible": false + }, + { + "name": "activeTimeMs", + "displayName": "Active time", + "computed": true, + "valueExpression": "{{ $['sum.activeTime'] === undefined || $['sum.activeTime'] === null ? null : $['sum.activeTime'] / 1000 }}", + "shape": "milliseconds" + }, + { + "name": "sum.cpuTime", + "displayName": "CPU time (µs)", + "shape": "number", + "visible": false + }, + { + "name": "cpuTimeMs", + "displayName": "CPU time", + "computed": true, + "valueExpression": "{{ $['sum.cpuTime'] === undefined || $['sum.cpuTime'] === null ? null : $['sum.cpuTime'] / 1000 }}", + "shape": "milliseconds" + }, + { + "name": "sum.rowsRead", + "displayName": "Rows read", + "shape": "number" + }, + { + "name": "sum.rowsWritten", + "displayName": "Rows written", + "shape": "number" + }, + { + "name": "sum.storageReadUnits", + "displayName": "Storage read units", + "shape": "number" + }, + { + "name": "sum.storageWriteUnits", + "displayName": "Storage write units", + "shape": "number" + }, + { + "name": "sum.subrequests", + "displayName": "Subrequests", + "shape": "number" + }, + { + "name": "sum.exceededCpuErrors", + "displayName": "CPU limit errors", + "shape": "number" + }, + { + "name": "sum.exceededMemoryErrors", + "displayName": "Memory limit errors", + "shape": "number" + }, + { + "name": "sum.fatalInternalErrors", + "displayName": "Internal errors", + "shape": "number" + }, + { + "name": "max.activeWebsocketConnections", + "displayName": "Peak WebSocket connections", + "shape": "number" + }, + { + "name": "max.memoryUsageBytes", + "displayName": "Peak memory", + "shape": "bytes" + } + ], + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth", + "lastMonth" + ] +} diff --git a/plugins/Cloudflare/v2/dataStreams/durableObjectInvocations.json b/plugins/Cloudflare/v2/dataStreams/durableObjectInvocations.json index ea14ba66..9c508489 100644 --- a/plugins/Cloudflare/v2/dataStreams/durableObjectInvocations.json +++ b/plugins/Cloudflare/v2/dataStreams/durableObjectInvocations.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$namespaceId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){durableObjectsInvocationsAdaptiveGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{requests errors responseBodySize wallTime}quantiles{wallTimeP50 wallTimeP90 wallTimeP99}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} status}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.durableObjectsInvocationsAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/durableObjectStorage.json b/plugins/Cloudflare/v2/dataStreams/durableObjectStorage.json index 605f04d0..43d77f9b 100644 --- a/plugins/Cloudflare/v2/dataStreams/durableObjectStorage.json +++ b/plugins/Cloudflare/v2/dataStreams/durableObjectStorage.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$namespaceId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){durableObjectsSqlStorageGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){max{storedBytes}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.durableObjectsSqlStorageGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/durableObjectSubrequests.json b/plugins/Cloudflare/v2/dataStreams/durableObjectSubrequests.json index cc5e40cf..c2b5629c 100644 --- a/plugins/Cloudflare/v2/dataStreams/durableObjectSubrequests.json +++ b/plugins/Cloudflare/v2/dataStreams/durableObjectSubrequests.json @@ -10,6 +10,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$namespaceId:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){durableObjectsSubrequestsAdaptiveGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{requestBodySizeUncached}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { @@ -19,8 +20,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.durableObjectsSubrequestsAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/emailRouting.json b/plugins/Cloudflare/v2/dataStreams/emailRouting.json index efa3e1c0..60adb9fd 100644 --- a/plugins/Cloudflare/v2/dataStreams/emailRouting.json +++ b/plugins/Cloudflare/v2/dataStreams/emailRouting.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){emailRoutingAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json b/plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json index 37138fc9..c9d4b986 100644 --- a/plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json +++ b/plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayResolverQueriesAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json b/plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json index d031cb08..5817cf64 100644 --- a/plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json +++ b/plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayL7RequestsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json b/plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json index ac97695d..01ce6953 100644 --- a/plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json +++ b/plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayL4SessionsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/hyperdrivePoolSizes.json b/plugins/Cloudflare/v2/dataStreams/hyperdrivePoolSizes.json new file mode 100644 index 00000000..e25c24b6 --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/hyperdrivePoolSizes.json @@ -0,0 +1,88 @@ +{ + "name": "hyperdrivePoolSizes", + "displayName": "Hyperdrive Connection Pool", + "description": "Connection pool size, free slots and waiting clients for a Hyperdrive config", + "tags": [ + "Storage", + "Analytics" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "headers": [ + { + "key": "X-Rate-Limit-Type", + "value": "account-based" + } + ], + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$configId:string!){viewer{accounts(filter:{accountTag:$accountTag}){hyperdrivePoolSizesAdaptiveGroups(limit:10000,filter:{configId:$configId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){avg{currentPoolSize availablePoolSlots waitingClients} max{maxPoolSize waitingClients} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} }}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "configId": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "graphqlRows.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Hyperdrive Config" + ] + } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "avg.currentPoolSize", + "displayName": "Pool size", + "shape": "number", + "role": "value", + "decimalPlaces": 1 + }, + { + "name": "avg.availablePoolSlots", + "displayName": "Free slots", + "shape": "number", + "decimalPlaces": 1 + }, + { + "name": "avg.waitingClients", + "displayName": "Waiting clients", + "shape": "number", + "decimalPlaces": 1 + }, + { + "name": "max.waitingClients", + "displayName": "Peak waiting clients", + "shape": "number" + }, + { + "name": "max.maxPoolSize", + "displayName": "Pool limit", + "shape": "number" + } + ], + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth" + ] +} diff --git a/plugins/Cloudflare/v2/dataStreams/hyperdriveQueries.json b/plugins/Cloudflare/v2/dataStreams/hyperdriveQueries.json index 66fb0604..332f9683 100644 --- a/plugins/Cloudflare/v2/dataStreams/hyperdriveQueries.json +++ b/plugins/Cloudflare/v2/dataStreams/hyperdriveQueries.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$configId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){hyperdriveQueriesAdaptiveGroups(limit:10000,filter:{configId:$configId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count avg{queryLatency} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.hyperdriveQueriesAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/imagesRequests.json b/plugins/Cloudflare/v2/dataStreams/imagesRequests.json index 82223801..5241f527 100644 --- a/plugins/Cloudflare/v2/dataStreams/imagesRequests.json +++ b/plugins/Cloudflare/v2/dataStreams/imagesRequests.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){imagesRequestsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){sum{requests}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/imagesTransformations.json b/plugins/Cloudflare/v2/dataStreams/imagesTransformations.json index aeee4a94..5d140f75 100644 --- a/plugins/Cloudflare/v2/dataStreams/imagesTransformations.json +++ b/plugins/Cloudflare/v2/dataStreams/imagesTransformations.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){imagesUniqueTransformations(limit:10000,filter:{date_geq:$start,date_leq:$end},orderBy:[date_ASC]){date transformations}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/kvOperations.json b/plugins/Cloudflare/v2/dataStreams/kvOperations.json index 7499da51..a57dfd2a 100644 --- a/plugins/Cloudflare/v2/dataStreams/kvOperations.json +++ b/plugins/Cloudflare/v2/dataStreams/kvOperations.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$namespaceId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){kvOperationsAdaptiveGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_DESC]){sum{requests}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} actionType}quantiles{latencyMsP50 latencyMsP90 latencyMsP99}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.kvOperationsAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "errorHandling": { "type": "path", "realm": "payload", diff --git a/plugins/Cloudflare/v2/dataStreams/kvStorage.json b/plugins/Cloudflare/v2/dataStreams/kvStorage.json index 30039b5a..9bb90fc7 100644 --- a/plugins/Cloudflare/v2/dataStreams/kvStorage.json +++ b/plugins/Cloudflare/v2/dataStreams/kvStorage.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$namespaceId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){kvStorageAdaptiveGroups(filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},limit:10000,orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_DESC]){max{keyCount byteCount}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.kvStorageAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "errorHandling": { "type": "path", "realm": "payload", diff --git a/plugins/Cloudflare/v2/dataStreams/pagesFunctionsInvocations.json b/plugins/Cloudflare/v2/dataStreams/pagesFunctionsInvocations.json index dbdb3b6e..c41adbfa 100644 --- a/plugins/Cloudflare/v2/dataStreams/pagesFunctionsInvocations.json +++ b/plugins/Cloudflare/v2/dataStreams/pagesFunctionsInvocations.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){pagesFunctionsInvocationsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{requests errors subrequests}quantiles{cpuTimeP50 cpuTimeP99}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} scriptName status}}}}}", "variables": { @@ -15,8 +16,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.pagesFunctionsInvocationsAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/pipelineIngestion.json b/plugins/Cloudflare/v2/dataStreams/pipelineIngestion.json index dd360cff..87129805 100644 --- a/plugins/Cloudflare/v2/dataStreams/pipelineIngestion.json +++ b/plugins/Cloudflare/v2/dataStreams/pipelineIngestion.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$pipelineId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){pipelinesIngestionAdaptiveGroups(limit:10000,filter:{pipelineId:$pipelineId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count sum{ingestedBytes ingestedRecords} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.pipelinesIngestionAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/queueBacklog.json b/plugins/Cloudflare/v2/dataStreams/queueBacklog.json index e6d90d60..786d4095 100644 --- a/plugins/Cloudflare/v2/dataStreams/queueBacklog.json +++ b/plugins/Cloudflare/v2/dataStreams/queueBacklog.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$queueId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){queueBacklogAdaptiveGroups(limit:10000,filter:{queueId:$queueId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){avg{messages bytes}dimensions{datetimeHour: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.queueBacklogAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/queueConsumerMetrics.json b/plugins/Cloudflare/v2/dataStreams/queueConsumerMetrics.json index 8d8c0836..e1c87fc0 100644 --- a/plugins/Cloudflare/v2/dataStreams/queueConsumerMetrics.json +++ b/plugins/Cloudflare/v2/dataStreams/queueConsumerMetrics.json @@ -10,6 +10,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$queueId:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){queueConsumerMetricsAdaptiveGroups(limit:10000,filter:{queueId:$queueId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){avg{concurrency}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { @@ -19,8 +20,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.queueConsumerMetricsAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/queueDelayedBacklog.json b/plugins/Cloudflare/v2/dataStreams/queueDelayedBacklog.json new file mode 100644 index 00000000..0b80af9e --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/queueDelayedBacklog.json @@ -0,0 +1,67 @@ +{ + "name": "queueDelayedBacklog", + "displayName": "Queue Delayed Backlog", + "description": "Average number of delayed messages waiting in a queue", + "tags": [ + "Storage", + "Analytics" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "headers": [ + { + "key": "X-Rate-Limit-Type", + "value": "account-based" + } + ], + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$queueId:string!){viewer{accounts(filter:{accountTag:$accountTag}){queueDelayedBacklogAdaptiveGroups(limit:10000,filter:{queueId:$queueId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){avg{messages} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} }}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "queueId": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "graphqlRows.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Queue" + ] + } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "avg.messages", + "displayName": "Delayed messages", + "shape": "number", + "role": "value", + "decimalPlaces": 1 + } + ], + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth", + "lastMonth" + ] +} diff --git a/plugins/Cloudflare/v2/dataStreams/queueMessageOperations.json b/plugins/Cloudflare/v2/dataStreams/queueMessageOperations.json index 7f9a64af..1bc1675d 100644 --- a/plugins/Cloudflare/v2/dataStreams/queueMessageOperations.json +++ b/plugins/Cloudflare/v2/dataStreams/queueMessageOperations.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$queueId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){queueMessageOperationsAdaptiveGroups(limit:10000,filter:{queueId:$queueId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){count sum{billableOperations bytes}avg{lagTime retryCount}max{messageSize}dimensions{datetimeHour: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} actionType outcome consumerType}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.queueMessageOperationsAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/r2Bandwidth.json b/plugins/Cloudflare/v2/dataStreams/r2Bandwidth.json new file mode 100644 index 00000000..795dd0f4 --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/r2Bandwidth.json @@ -0,0 +1,70 @@ +{ + "name": "r2Bandwidth", + "displayName": "R2 Bandwidth", + "description": "Bytes downloaded from and uploaded to an R2 bucket", + "tags": [ + "Storage", + "Analytics" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "headers": [ + { + "key": "X-Rate-Limit-Type", + "value": "account-based" + } + ], + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$bucketName:string!){viewer{accounts(filter:{accountTag:$accountTag}){r2BandwidthUsageAdaptiveGroups(limit:10000,filter:{bucketName:$bucketName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){sum{bytesDownload bytesUpload} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} }}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "bucketName": "{{object.name}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "graphqlRows.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare R2 Bucket" + ] + } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "sum.bytesDownload", + "displayName": "Downloaded", + "shape": "bytes", + "role": "value" + }, + { + "name": "sum.bytesUpload", + "displayName": "Uploaded", + "shape": "bytes" + } + ], + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth" + ] +} diff --git a/plugins/Cloudflare/v2/dataStreams/r2Operations.json b/plugins/Cloudflare/v2/dataStreams/r2Operations.json index 27f8b57a..2ceb5da5 100644 --- a/plugins/Cloudflare/v2/dataStreams/r2Operations.json +++ b/plugins/Cloudflare/v2/dataStreams/r2Operations.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$bucketName:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){r2OperationsAdaptiveGroups(limit:10000,filter:{bucketName:$bucketName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : 'date' }}_ASC]){sum{requests responseBytes}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : 'date' }} actionType actionStatus}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.r2OperationsAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/r2Storage.json b/plugins/Cloudflare/v2/dataStreams/r2Storage.json index 561eaa17..af84de12 100644 --- a/plugins/Cloudflare/v2/dataStreams/r2Storage.json +++ b/plugins/Cloudflare/v2/dataStreams/r2Storage.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$bucketName:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){r2StorageAdaptiveGroups(limit:10000,filter:{bucketName:$bucketName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){max{objectCount payloadSize metadataSize uploadCount}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.r2StorageAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/realtimeUsage.json b/plugins/Cloudflare/v2/dataStreams/realtimeUsage.json index e4573783..e63359b2 100644 --- a/plugins/Cloudflare/v2/dataStreams/realtimeUsage.json +++ b/plugins/Cloudflare/v2/dataStreams/realtimeUsage.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$appId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){callsUsageAdaptiveGroups(limit:10000,filter:{appId:$appId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){sum{egressBytes ingressBytes} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} trackType}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.callsUsageAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/rumPageLoadTiming.json b/plugins/Cloudflare/v2/dataStreams/rumPageLoadTiming.json new file mode 100644 index 00000000..6eea5a64 --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/rumPageLoadTiming.json @@ -0,0 +1,150 @@ +{ + "name": "rumPageLoadTiming", + "displayName": "Web Analytics Page Load Timing", + "description": "P75 page load timing breakdown (DNS, connection, request, response, first contentful paint, page load) for a zone's hostnames", + "tags": [ + "Zone", + "Analytics" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "headers": [ + { + "key": "X-Rate-Limit-Type", + "value": "account-based" + } + ], + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$hostFilter:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumPerformanceEventsAdaptiveGroups(limit:10000,filter:{requestHost_like:$hostFilter,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count sum{visits} quantiles{dnsTimeP75 connectionTimeP75 requestTimeP75 responseTimeP75 firstContentfulPaintP75 pageLoadTimeP75} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} }}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "hostFilter": "{{'%' + object.name}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "graphqlRows.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Zone" + ] + } + }, + "metadata": [ + { + "name": "dimensions.date", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "count", + "displayName": "Page loads", + "shape": "number", + "role": "value" + }, + { + "name": "sum.visits", + "displayName": "Visits", + "shape": "number" + }, + { + "name": "dnsTime", + "displayName": "DNS P75", + "computed": true, + "valueExpression": "{{ $['quantiles.dnsTimeP75'] === undefined || $['quantiles.dnsTimeP75'] === null ? null : $['quantiles.dnsTimeP75'] / 1000 }}", + "shape": "milliseconds" + }, + { + "name": "connectionTime", + "displayName": "Connection P75", + "computed": true, + "valueExpression": "{{ $['quantiles.connectionTimeP75'] === undefined || $['quantiles.connectionTimeP75'] === null ? null : $['quantiles.connectionTimeP75'] / 1000 }}", + "shape": "milliseconds" + }, + { + "name": "requestTime", + "displayName": "Request P75", + "computed": true, + "valueExpression": "{{ $['quantiles.requestTimeP75'] === undefined || $['quantiles.requestTimeP75'] === null ? null : $['quantiles.requestTimeP75'] / 1000 }}", + "shape": "milliseconds" + }, + { + "name": "responseTime", + "displayName": "Response P75", + "computed": true, + "valueExpression": "{{ $['quantiles.responseTimeP75'] === undefined || $['quantiles.responseTimeP75'] === null ? null : $['quantiles.responseTimeP75'] / 1000 }}", + "shape": "milliseconds" + }, + { + "name": "firstContentfulPaint", + "displayName": "First contentful paint P75", + "computed": true, + "valueExpression": "{{ $['quantiles.firstContentfulPaintP75'] === undefined || $['quantiles.firstContentfulPaintP75'] === null ? null : $['quantiles.firstContentfulPaintP75'] / 1000 }}", + "shape": "milliseconds" + }, + { + "name": "pageLoadTime", + "displayName": "Page load P75", + "computed": true, + "valueExpression": "{{ $['quantiles.pageLoadTimeP75'] === undefined || $['quantiles.pageLoadTimeP75'] === null ? null : $['quantiles.pageLoadTimeP75'] / 1000 }}", + "shape": "milliseconds" + }, + { + "name": "quantiles.dnsTimeP75", + "displayName": "dnsTimeP75", + "shape": "number", + "visible": false + }, + { + "name": "quantiles.connectionTimeP75", + "displayName": "connectionTimeP75", + "shape": "number", + "visible": false + }, + { + "name": "quantiles.requestTimeP75", + "displayName": "requestTimeP75", + "shape": "number", + "visible": false + }, + { + "name": "quantiles.responseTimeP75", + "displayName": "responseTimeP75", + "shape": "number", + "visible": false + }, + { + "name": "quantiles.firstContentfulPaintP75", + "displayName": "firstContentfulPaintP75", + "shape": "number", + "visible": false + }, + { + "name": "quantiles.pageLoadTimeP75", + "displayName": "pageLoadTimeP75", + "shape": "number", + "visible": false + } + ], + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth", + "lastMonth", + "thisQuarter" + ] +} diff --git a/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json b/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json index f57196c9..399b3ff1 100644 --- a/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json +++ b/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!,$requestHost:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumPageloadEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end,requestHost_like:$requestHost},orderBy:[count_DESC]){count sum{visits} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json b/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json index 38ef5759..00de4dfc 100644 --- a/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json +++ b/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!,$hostFilter:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumWebVitalsEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end,requestHost_like:$hostFilter},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}} quantiles{largestContentfulPaintP75 interactionToNextPaintP75 firstInputDelayP75 cumulativeLayoutShiftP75}}}}}", "variables": { @@ -16,8 +17,7 @@ "hostFilter": "{{'%' + object.name}}" } }, - "expandInnerObjects": true, - "pathToData": "data.viewer.accounts.0.rumWebVitalsEventsAdaptiveGroups", + "postRequestScript": "graphqlRows.js", "errorHandling": { "type": "path", "realm": "payload", diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/accountTraffic.js b/plugins/Cloudflare/v2/dataStreams/scripts/accountTraffic.js new file mode 100644 index 00000000..8c30c09e --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/scripts/accountTraffic.js @@ -0,0 +1,34 @@ +// Cloudflare answers HTTP 200 even when the GraphQL query failed, so raise the +// errors array here or the tile would show no data instead of the reason. +if (data && data.errors && data.errors.length) { + api.report.error("Cloudflare GraphQL error: " + data.errors.map((e) => e && e.message).join(" | ")); +} + +// dataStreams/scripts/accountTraffic.js +// httpRequestsAdaptiveGroups at account level covers every zone in the account in one +// query. The selected breakdown dimension is interpolated into the query, so its value +// sits under a different key per breakdown; normalise it to a stable `breakdown` column. +// When the breakdown is the zone, the zone tag is also emitted as `zoneTag`, which the +// stream's metadata resolves to the imported zone's name. + +const account = (context.objects && context.objects[0]) || {}; +const dimensionKey = (context.config && context.config.breakdown) || "zoneTag"; + +const accounts = (data && data.data && data.data.viewer && data.data.viewer.accounts) || []; +const groups = (accounts[0] || {}).httpRequestsAdaptiveGroups || []; + +result = groups.map((row) => { + const dims = row.dimensions || {}; + const sum = row.sum || {}; + const raw = dims[dimensionKey]; + const value = raw === undefined || raw === null || raw === "" ? "Unknown" : String(raw); + return { + datetime: dims.datetime, + breakdown: value, + zoneTag: dimensionKey === "zoneTag" ? value : null, + requests: Number(row.count || 0) || 0, + bytes: Number(sum.edgeResponseBytes || 0) || 0, + visits: Number(sum.visits || 0) || 0, + accountName: account.name || account.rawId || "", + }; +}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/graphqlRows.js b/plugins/Cloudflare/v2/dataStreams/scripts/graphqlRows.js new file mode 100644 index 00000000..b20c41de --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/scripts/graphqlRows.js @@ -0,0 +1,55 @@ +// dataStreams/scripts/graphqlRows.js +// Shared by the GraphQL analytics streams that need no shaping of their own. Each of +// those queries selects a single dataset under one account or one zone, so the rows are +// the one array found at data.viewer.[0].. +// +// A script rather than pathToData because Cloudflare answers a failed GraphQL query with +// HTTP 200 and an `errors` array, which the declarative errorHandling never sees: the +// tile would show no data instead of the reason (an unentitled feature, or a timeframe +// wider than the plan allows). +// +// Rows are flattened to dotted column names (sum.requests, dimensions.date) exactly as +// expandInnerObjects did, so the streams' metadata and dashboards are unchanged. + +const body = data || {}; + +const errors = Array.isArray(body.errors) ? body.errors : []; +if (errors.length) { + api.report.error( + "Cloudflare GraphQL error: " + + errors.map((e) => (e && e.message) || JSON.stringify(e)).join(" | ") + ); +} + +const viewer = (body.data && body.data.viewer) || {}; +const scope = (viewer.accounts || viewer.zones || [])[0] || {}; +const rows = Object.keys(scope) + .map((key) => scope[key]) + .find((value) => Array.isArray(value)) || []; + +const flatten = (value, prefix, target) => { + Object.keys(value).forEach((key) => { + const item = value[key]; + const name = prefix ? prefix + "." + key : key; + if (item !== null && typeof item === "object" && !Array.isArray(item)) { + flatten(item, name, target); + } else { + target[name] = item; + } + }); + return target; +}; + +// Streams with a `breakdown` parameter interpolate the chosen dimension into the query, +// so its column name varies (dimensions.hostname, dimensions.cacheStatus, ...). Copy it +// to a stable `breakdown` column for tiles to group on. +const breakdownKey = context.config && context.config.breakdown; + +result = rows.map((row) => { + const flat = flatten(row, "", {}); + if (breakdownKey) { + const value = row.dimensions && row.dimensions[breakdownKey]; + flat.breakdown = value === undefined || value === null || value === "" ? "Unknown" : String(value); + } + return flat; +}); diff --git a/plugins/Cloudflare/v2/dataStreams/streamCmcd.json b/plugins/Cloudflare/v2/dataStreams/streamCmcd.json index b2323bf3..885c49f0 100644 --- a/plugins/Cloudflare/v2/dataStreams/streamCmcd.json +++ b/plugins/Cloudflare/v2/dataStreams/streamCmcd.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$videoId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){streamCMCDAdaptiveGroups(limit:10000,filter:{videoId:$videoId,datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count avg{bufferStarvationDuration initialBufferStarvationDuration encodedBitrate} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/streamMinutesViewed.json b/plugins/Cloudflare/v2/dataStreams/streamMinutesViewed.json index 25f1f84b..04ce1d80 100644 --- a/plugins/Cloudflare/v2/dataStreams/streamMinutesViewed.json +++ b/plugins/Cloudflare/v2/dataStreams/streamMinutesViewed.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$uid:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){streamMinutesViewedAdaptiveGroups(limit:10000,filter:{uid:$uid,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}sum{minutesViewed}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.streamMinutesViewedAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json b/plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json index 781458d6..271153f6 100644 --- a/plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json +++ b/plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$siteKey:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){turnstileAdaptiveGroups(limit:5000,filter:{siteKey:$siteKey,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/vectorizeQueries.json b/plugins/Cloudflare/v2/dataStreams/vectorizeQueries.json index a2e065a6..a0cb1924 100644 --- a/plugins/Cloudflare/v2/dataStreams/vectorizeQueries.json +++ b/plugins/Cloudflare/v2/dataStreams/vectorizeQueries.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$indexName:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){vectorizeV2QueriesAdaptiveGroups(limit:10000,filter:{indexName:$indexName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count avg{requestDurationMs} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.vectorizeV2QueriesAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/vectorizeStorage.json b/plugins/Cloudflare/v2/dataStreams/vectorizeStorage.json index b809eafc..0b7b0454 100644 --- a/plugins/Cloudflare/v2/dataStreams/vectorizeStorage.json +++ b/plugins/Cloudflare/v2/dataStreams/vectorizeStorage.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$indexName:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){vectorizeV2StorageAdaptiveGroups(limit:10000,filter:{indexName:$indexName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){max{storedVectorDimensions vectorCount} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { @@ -16,8 +17,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.vectorizeV2StorageAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/workerBuildMinutes.json b/plugins/Cloudflare/v2/dataStreams/workerBuildMinutes.json new file mode 100644 index 00000000..1e9d08e3 --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/workerBuildMinutes.json @@ -0,0 +1,63 @@ +{ + "name": "workerBuildMinutes", + "displayName": "Workers Build Minutes", + "description": "Workers Builds minutes used by an account", + "tags": [ + "Compute" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "headers": [ + { + "key": "X-Rate-Limit-Type", + "value": "account-based" + } + ], + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){workersBuildsBuildMinutesAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){sum{buildMinutes} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} }}}}}", + "variables": { + "accountTag": "{{object.rawId}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "graphqlRows.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Account" + ] + } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "sum.buildMinutes", + "displayName": "Build minutes", + "shape": "number", + "role": "value" + } + ], + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth" + ] +} diff --git a/plugins/Cloudflare/v2/dataStreams/workerCacheRequests.json b/plugins/Cloudflare/v2/dataStreams/workerCacheRequests.json new file mode 100644 index 00000000..ae7ce029 --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/workerCacheRequests.json @@ -0,0 +1,72 @@ +{ + "name": "workerCacheRequests", + "displayName": "Worker Cache Requests", + "description": "Cache API requests made by a Worker script by cache status", + "tags": [ + "Compute", + "Analytics" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "headers": [ + { + "key": "X-Rate-Limit-Type", + "value": "account-based" + } + ], + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$scriptName:string!){viewer{accounts(filter:{accountTag:$accountTag}){workersCacheRequestsAdaptiveGroups(limit:10000,filter:{scriptName:$scriptName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{requests} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} cacheStatus }}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "scriptName": "{{object.name}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "graphqlRows.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Worker" + ] + } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "dimensions.cacheStatus", + "displayName": "Cache status", + "shape": "string", + "role": "label" + }, + { + "name": "sum.requests", + "displayName": "Requests", + "shape": "number", + "role": "value" + } + ], + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth", + "lastMonth" + ] +} diff --git a/plugins/Cloudflare/v2/dataStreams/workerCronRuns.json b/plugins/Cloudflare/v2/dataStreams/workerCronRuns.json new file mode 100644 index 00000000..a61d27a9 --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/workerCronRuns.json @@ -0,0 +1,110 @@ +{ + "name": "workerCronRuns", + "displayName": "Worker Cron Trigger Runs", + "description": "Each scheduled (cron trigger) run of a Worker script with its schedule, outcome and CPU time", + "tags": [ + "Compute" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "headers": [ + { + "key": "X-Rate-Limit-Type", + "value": "account-based" + } + ], + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$scriptName:string!){viewer{accounts(filter:{accountTag:$accountTag}){workersInvocationsScheduled(limit:1000,filter:{scriptName:$scriptName,datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_DESC]){datetime scheduledDatetime cron status cpuTimeUs}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "scriptName": "{{object.name}}", + "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "graphqlRows.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Worker" + ] + } + }, + "metadata": [ + { + "name": "datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "scheduledDatetime", + "displayName": "Scheduled for", + "shape": "date" + }, + { + "name": "cron", + "displayName": "Schedule", + "shape": "string", + "role": "label" + }, + { + "name": "status", + "displayName": "Status", + "shape": "string" + }, + { + "name": "statusState", + "displayName": "Outcome", + "computed": true, + "valueExpression": "{{ $['status'] }}", + "shape": [ + "state", + { + "map": { + "success": [ + "success" + ], + "error": [ + "error", + "exceededCpu", + "exceededMemory", + "exceededResources", + "scriptThrewException", + "internalError", + "unknown" + ] + } + } + ] + }, + { + "name": "cpuTimeUs", + "displayName": "CPU time (µs)", + "shape": "number", + "visible": false + }, + { + "name": "cpuTime", + "displayName": "CPU time", + "computed": true, + "valueExpression": "{{ $['cpuTimeUs'] === undefined || $['cpuTimeUs'] === null ? null : $['cpuTimeUs'] / 1000 }}", + "shape": "milliseconds" + } + ], + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days" + ] +} diff --git a/plugins/Cloudflare/v2/dataStreams/workerInvocations.json b/plugins/Cloudflare/v2/dataStreams/workerInvocations.json index 1332fa2c..3cea310b 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerInvocations.json +++ b/plugins/Cloudflare/v2/dataStreams/workerInvocations.json @@ -10,6 +10,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$scriptName:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){workersInvocationsAdaptive(limit:10000,filter:{scriptName:$scriptName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{requests errors subrequests}quantiles{cpuTimeP50 cpuTimeP99}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} status scriptName}}}}}", "variables": { @@ -19,8 +20,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.accounts.0.workersInvocationsAdaptive", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "errorHandling": { "type": "path", "realm": "payload", diff --git a/plugins/Cloudflare/v2/dataStreams/workerSmartPlacement.json b/plugins/Cloudflare/v2/dataStreams/workerSmartPlacement.json new file mode 100644 index 00000000..110118a5 --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/workerSmartPlacement.json @@ -0,0 +1,86 @@ +{ + "name": "workerSmartPlacement", + "displayName": "Worker Smart Placement", + "description": "Requests and duration for a Worker script split by whether Smart Placement ran it near its back end", + "tags": [ + "Compute", + "Analytics" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "headers": [ + { + "key": "X-Rate-Limit-Type", + "value": "account-based" + } + ], + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$scriptName:string!){viewer{accounts(filter:{accountTag:$accountTag}){workerPlacementAdaptiveGroups(limit:10000,filter:{scriptName:$scriptName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{requests requestDuration} quantiles{requestDurationP50 requestDurationP99} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} placementUsed }}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "scriptName": "{{object.name}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "graphqlRows.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Worker" + ] + } + }, + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "dimensions.placementUsed", + "displayName": "Placement used", + "shape": "string", + "role": "label" + }, + { + "name": "sum.requests", + "displayName": "Requests", + "shape": "number", + "role": "value" + }, + { + "name": "sum.requestDuration", + "displayName": "Total duration", + "shape": "milliseconds" + }, + { + "name": "quantiles.requestDurationP50", + "displayName": "Duration P50", + "shape": "milliseconds" + }, + { + "name": "quantiles.requestDurationP99", + "displayName": "Duration P99", + "shape": "milliseconds" + } + ], + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth" + ] +} diff --git a/plugins/Cloudflare/v2/dataStreams/workerStaticAssets.json b/plugins/Cloudflare/v2/dataStreams/workerStaticAssets.json new file mode 100644 index 00000000..bfb8a1f8 --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/workerStaticAssets.json @@ -0,0 +1,94 @@ +{ + "name": "workerStaticAssets", + "displayName": "Worker Static Asset Requests", + "description": "Requests served from a Worker script's static assets, grouped by a selectable dimension", + "tags": [ + "Compute", + "Analytics" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "headers": [ + { + "key": "X-Rate-Limit-Type", + "value": "account-based" + } + ], + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$scriptName:string!){viewer{accounts(filter:{accountTag:$accountTag}){workersAssetsRequestsAdaptiveGroups(limit:10000,filter:{scriptName:$scriptName,datetime_geq:$start,datetime_leq:$end},orderBy:[sum_requests_DESC]){sum{requests} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown || 'statusCode'}} }}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "scriptName": "{{object.name}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "graphqlRows.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Worker" + ] + } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "statusCode", + "options": [ + { + "value": "statusCode", + "label": "Status code" + }, + { + "value": "cacheStatus", + "label": "Cache status" + }, + { + "value": "hostname", + "label": "Host" + } + ] + } + ], + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "sum.requests", + "displayName": "Requests", + "shape": "number", + "role": "value" + } + ], + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth" + ] +} diff --git a/plugins/Cloudflare/v2/dataStreams/workerSubrequests.json b/plugins/Cloudflare/v2/dataStreams/workerSubrequests.json new file mode 100644 index 00000000..ecb6adb6 --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/workerSubrequests.json @@ -0,0 +1,135 @@ +{ + "name": "workerSubrequests", + "displayName": "Worker Subrequests", + "description": "Outbound subrequests made by a Worker script, with response time, grouped by a selectable dimension", + "tags": [ + "Compute", + "Analytics" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "headers": [ + { + "key": "X-Rate-Limit-Type", + "value": "account-based" + } + ], + "postBody": { + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$scriptName:string!){viewer{accounts(filter:{accountTag:$accountTag}){workersSubrequestsAdaptiveGroups(limit:10000,filter:{scriptName:$scriptName,datetime_geq:$start,datetime_leq:$end},orderBy:[sum_subrequests_DESC]){sum{subrequests requestBodySize responseBodySize} quantiles{timeToResponseUsP50 timeToResponseUsP99} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown || 'hostname'}} }}}}}", + "variables": { + "accountTag": "{{object.accountId}}", + "scriptName": "{{object.name}}", + "start": "{{timeframe.start}}", + "end": "{{timeframe.end}}" + } + }, + "postRequestScript": "graphqlRows.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Worker" + ] + } + }, + "ui": [ + { + "type": "choiceChips", + "name": "breakdown", + "label": "Breakdown", + "required": true, + "defaultValue": "hostname", + "options": [ + { + "value": "hostname", + "label": "Host" + }, + { + "value": "cacheStatus", + "label": "Cache status" + }, + { + "value": "httpResponseStatus", + "label": "Status code" + }, + { + "value": "requestOutcome", + "label": "Outcome" + } + ] + } + ], + "metadata": [ + { + "name": "dimensions.datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "breakdown", + "displayName": "Breakdown", + "shape": "string", + "role": "label" + }, + { + "name": "sum.subrequests", + "displayName": "Subrequests", + "shape": "number", + "role": "value" + }, + { + "name": "sum.requestBodySize", + "displayName": "Request bytes", + "shape": "bytes" + }, + { + "name": "sum.responseBodySize", + "displayName": "Response bytes", + "shape": "bytes" + }, + { + "name": "quantiles.timeToResponseUsP50", + "displayName": "Response time P50 (µs)", + "shape": "number", + "visible": false + }, + { + "name": "quantiles.timeToResponseUsP99", + "displayName": "Response time P99 (µs)", + "shape": "number", + "visible": false + }, + { + "name": "responseTimeP50", + "displayName": "Response time P50", + "computed": true, + "valueExpression": "{{ $['quantiles.timeToResponseUsP50'] === undefined || $['quantiles.timeToResponseUsP50'] === null ? null : $['quantiles.timeToResponseUsP50'] / 1000 }}", + "shape": "milliseconds" + }, + { + "name": "responseTimeP99", + "displayName": "Response time P99", + "computed": true, + "valueExpression": "{{ $['quantiles.timeToResponseUsP99'] === undefined || $['quantiles.timeToResponseUsP99'] === null ? null : $['quantiles.timeToResponseUsP99'] / 1000 }}", + "shape": "milliseconds" + } + ], + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days", + "thisMonth", + "lastMonth" + ] +} diff --git a/plugins/Cloudflare/v2/dataStreams/workersAiInference.json b/plugins/Cloudflare/v2/dataStreams/workersAiInference.json index 39656770..c40185af 100644 --- a/plugins/Cloudflare/v2/dataStreams/workersAiInference.json +++ b/plugins/Cloudflare/v2/dataStreams/workersAiInference.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiInferenceAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count sum{totalInputTokens totalOutputTokens totalInferenceTimeMs}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json b/plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json index f326e606..e9cf4434 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){dnsAnalyticsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count avg{processingTimeUs} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventVolume.json b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventVolume.json index 609f7ca5..f6669b4c 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventVolume.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventVolume.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$filter:ZoneFirewallEventsAdaptiveByTimeGroupsFilter_InputObject){viewer{zones(filter:{zoneTag:$zoneTag}){firewallEventsAdaptiveByTimeGroups(limit:10000,filter:$filter,orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json index 93c05b0b..b61d50a1 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){firewallEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{action {{breakdown}} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/zoneHealthCheckEvents.json b/plugins/Cloudflare/v2/dataStreams/zoneHealthCheckEvents.json index 60c04d45..b57b67c8 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneHealthCheckEvents.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneHealthCheckEvents.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){healthCheckEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count avg{rttMs}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} healthCheckName healthCheckId healthStatus healthChanged failureReason region originIP}}}}}", "variables": { @@ -15,8 +16,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.zones.0.healthCheckEventsAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/zoneLoadBalancing.json b/plugins/Cloudflare/v2/dataStreams/zoneLoadBalancing.json index e503fb18..1cf21eeb 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneLoadBalancing.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneLoadBalancing.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){loadBalancingRequestsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{lbName selectedPoolName selectedOriginName coloCode}}}}}", "variables": { @@ -15,8 +16,7 @@ "end": "{{timeframe.end}}" } }, - "pathToData": "data.viewer.zones.0.loadBalancingRequestsAdaptiveGroups", - "expandInnerObjects": true, + "postRequestScript": "graphqlRows.js", "errorHandling": { "type": "path", "realm": "payload", diff --git a/plugins/Cloudflare/v2/dataStreams/zoneNelReports.json b/plugins/Cloudflare/v2/dataStreams/zoneNelReports.json index bcb36438..3b57d85c 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneNelReports.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneNelReports.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){nelReportsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/zonePageShield.json b/plugins/Cloudflare/v2/dataStreams/zonePageShield.json index 8fbf35f4..1767fb6b 100644 --- a/plugins/Cloudflare/v2/dataStreams/zonePageShield.json +++ b/plugins/Cloudflare/v2/dataStreams/zonePageShield.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){pageShieldReportsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/zoneTraffic.json b/plugins/Cloudflare/v2/dataStreams/zoneTraffic.json index df15f906..66e54a51 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneTraffic.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneTraffic.json @@ -10,6 +10,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:{{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'Time!' : 'Date!' }},$end:{{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'Time!' : 'Date!' }}){viewer{zones(filter:{zoneTag:$zoneTag}){rows: {{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'httpRequests1hGroups' : 'httpRequests1dGroups' }}(limit:10000,filter:{ {{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'datetime' : 'date' }}_geq:$start, {{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'datetime' : 'date' }}_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'datetime' : 'date' }}_ASC]){dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'datetime' : 'date' }}}sum{requests cachedRequests bytes cachedBytes threats pageViews encryptedRequests}uniq{uniques}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json b/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json index 37889c29..f9f84350 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json @@ -7,6 +7,7 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", + "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){httpRequestsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count sum{edgeResponseBytes visits} dimensions{ {{breakdown}} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/defaultContent/Compute/durableObjectNamespace.dash.json b/plugins/Cloudflare/v2/defaultContent/Compute/durableObjectNamespace.dash.json index cb0ee505..869e46a5 100644 --- a/plugins/Cloudflare/v2/defaultContent/Compute/durableObjectNamespace.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Compute/durableObjectNamespace.dash.json @@ -639,6 +639,230 @@ } } } + }, + { + "i": "6040902c-b829-4c63-8dd5-b1247233ae98", + "x": 0, + "y": 14, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Active and CPU Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[durableObjectActivity]}}", + "name": "durableObjectActivity", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Durable Object Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare Durable Object Namespace]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime", + "yAxisColumn": [ + "activeTimeMs", + "cpuTimeMs" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "a43d0eed-2080-45aa-8290-23f0242cbea2", + "x": 2, + "y": 14, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Peak Memory", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[durableObjectActivity]}}", + "name": "durableObjectActivity", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Durable Object Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare Durable Object Namespace]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime", + "yAxisColumn": [ + "max.memoryUsageBytes" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "fb5f350c-d155-46e7-89d4-143ae7d9e770", + "x": 0, + "y": 17, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Storage Operations", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[durableObjectActivity]}}", + "name": "durableObjectActivity", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Durable Object Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare Durable Object Namespace]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime", + "yAxisColumn": [ + "sum.rowsRead", + "sum.rowsWritten" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "f08d883b-6f7b-497e-8c3a-c83ac356f278", + "x": 2, + "y": 17, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Limit and Internal Errors", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[durableObjectActivity]}}", + "name": "durableObjectActivity", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Durable Object Namespace]}}" + }, + "variables": [ + "{{variables.[Cloudflare Durable Object Namespace]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime", + "yAxisColumn": [ + "sum.exceededCpuErrors", + "sum.exceededMemoryErrors", + "sum.fatalInternalErrors" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } } ] } diff --git a/plugins/Cloudflare/v2/defaultContent/Compute/queue.dash.json b/plugins/Cloudflare/v2/defaultContent/Compute/queue.dash.json index 25bc734b..7e7220f0 100644 --- a/plugins/Cloudflare/v2/defaultContent/Compute/queue.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Compute/queue.dash.json @@ -614,6 +614,61 @@ } } } + }, + { + "i": "a86dfd13-0577-4b29-8335-fff93d5e007a", + "x": 0, + "y": 14, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Delayed Messages", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[queueDelayedBacklog]}}", + "name": "queueDelayedBacklog", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Queues]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Queue]}}" + }, + "variables": [ + "{{variables.[Cloudflare Queue]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime", + "yAxisColumn": [ + "avg.messages" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } } ] } diff --git a/plugins/Cloudflare/v2/defaultContent/Compute/worker.dash.json b/plugins/Cloudflare/v2/defaultContent/Compute/worker.dash.json index 64abe644..7a7a4170 100644 --- a/plugins/Cloudflare/v2/defaultContent/Compute/worker.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Compute/worker.dash.json @@ -489,6 +489,392 @@ } } } + }, + { + "i": "4fb0038e-6c55-4a4a-bcbc-382dd2d96f4d", + "x": 0, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Subrequests by Host", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerSubrequests]}}", + "name": "workerSubrequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "hostname" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.subrequests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "sum.subrequests_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Workers]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Worker]}}" + }, + "variables": [ + "{{variables.[Cloudflare Worker]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "sum.subrequests_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "horizontal", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "58470c3e-ba46-4207-8867-298f50da1905", + "x": 2, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Subrequest Response Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerSubrequests]}}", + "name": "workerSubrequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "hostname" + }, + "group": { + "by": [ + [ + "dimensions.datetime", + "byHour" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "responseTimeP50" + ] + }, + { + "type": "mean", + "names": [ + "responseTimeP99" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Workers]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Worker]}}" + }, + "variables": [ + "{{variables.[Cloudflare Worker]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byHour", + "yAxisColumn": [ + "responseTimeP50_mean", + "responseTimeP99_mean" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "c3e01082-afaa-4e6d-95af-3e3170e41715", + "x": 0, + "y": 11, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Cron Trigger Runs", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerCronRuns]}}", + "name": "workerCronRuns", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "datetime", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Workers]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Worker]}}" + }, + "variables": [ + "{{variables.[Cloudflare Worker]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "datetime", + "cron", + "statusState", + "cpuTime", + "scheduledDatetime" + ], + "hiddenColumns": [ + "status", + "cpuTimeUs" + ] + } + } + }, + "timeframe": "last7days" + } + }, + { + "i": "e2827126-91cf-4d52-b66e-7a753b1c633e", + "x": 0, + "y": 14, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Static Asset Requests", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerStaticAssets]}}", + "name": "workerStaticAssets", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "statusCode" + }, + "sort": { + "by": [ + [ + "dimensions.datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Workers]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Worker]}}" + }, + "variables": [ + "{{variables.[Cloudflare Worker]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime", + "yAxisColumn": [ + "sum.requests" + ], + "seriesColumn": "breakdown", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "55e8a7cf-6c81-4a32-925c-5f9717439bcc", + "x": 2, + "y": 14, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Cache API Requests", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerCacheRequests]}}", + "name": "workerCacheRequests", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Workers]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Worker]}}" + }, + "variables": [ + "{{variables.[Cloudflare Worker]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime", + "yAxisColumn": [ + "sum.requests" + ], + "seriesColumn": "dimensions.cacheStatus", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "64b62cb5-f7e9-406e-afb3-ef551c6b3ee4", + "x": 0, + "y": 17, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Smart Placement Duration (P50)", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerSmartPlacement]}}", + "name": "workerSmartPlacement", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Workers]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Worker]}}" + }, + "variables": [ + "{{variables.[Cloudflare Worker]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime", + "yAxisColumn": [ + "quantiles.requestDurationP50" + ], + "seriesColumn": "dimensions.placementUsed", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } } ] } diff --git a/plugins/Cloudflare/v2/defaultContent/Core/account.dash.json b/plugins/Cloudflare/v2/defaultContent/Core/account.dash.json index 4dd20781..c74e708c 100644 --- a/plugins/Cloudflare/v2/defaultContent/Core/account.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Core/account.dash.json @@ -2946,6 +2946,303 @@ } } } + }, + { + "i": "36f99add-606b-4848-8e56-7dfdf94c824b", + "x": 0, + "y": 65, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Requests by Zone", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accountTraffic]}}", + "name": "accountTraffic", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "zoneTag" + }, + "sort": { + "by": [ + [ + "datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "datetime", + "yAxisColumn": [ + "requests" + ], + "seriesColumn": "zoneName", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + }, + "timeframe": "last24hours" + } + }, + { + "i": "2789dab8-bd9d-4cf9-b5d4-9e1ed480084f", + "x": 0, + "y": 68, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Traffic by Country", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accountTraffic]}}", + "name": "accountTraffic", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "clientCountryName" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "requests_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "requests_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "horizontal", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + }, + "timeframe": "last24hours" + } + }, + { + "i": "8eb403cb-7ab9-46b2-84df-2aa0ed1c22ca", + "x": 2, + "y": 68, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Traffic by Status Code", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accountTraffic]}}", + "name": "accountTraffic", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "edgeResponseStatus" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "requests_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "requests_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "horizontal", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + }, + "timeframe": "last24hours" + } + }, + { + "i": "a92b1e43-9903-4d5d-9941-6dd4c1e7f726", + "x": 0, + "y": 71, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Workers Build Minutes", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerBuildMinutes]}}", + "name": "workerBuildMinutes", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetime", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.buildMinutes" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byDay", + "yAxisColumn": [ + "sum.buildMinutes_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + }, + "timeframe": "last30days" + } } ] } diff --git a/plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json b/plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json index f32c0b74..4e07a502 100644 --- a/plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json @@ -3056,6 +3056,67 @@ } } } + }, + { + "i": "7777d765-1ec1-470d-8e6a-6c70e15637a9", + "x": 0, + "y": 66, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Page Load Timing (P75)", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumPageLoadTiming]}}", + "name": "rumPageLoadTiming", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.date", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date", + "yAxisColumn": [ + "dnsTime", + "connectionTime", + "requestTime", + "responseTime", + "firstContentfulPaint", + "pageLoadTime" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + }, + "timeframe": "last7days" + } } ] } diff --git a/plugins/Cloudflare/v2/defaultContent/Storage & Databases/hyperdriveConfig.dash.json b/plugins/Cloudflare/v2/defaultContent/Storage & Databases/hyperdriveConfig.dash.json index d2c1ee83..f6d6c1ec 100644 --- a/plugins/Cloudflare/v2/defaultContent/Storage & Databases/hyperdriveConfig.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Storage & Databases/hyperdriveConfig.dash.json @@ -407,6 +407,118 @@ } } } + }, + { + "i": "d5484d9b-0e56-4e3b-8ca0-b73c5047827f", + "x": 0, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Connection Pool", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[hyperdrivePoolSizes]}}", + "name": "hyperdrivePoolSizes", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Hyperdrive Configs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Hyperdrive Config]}}" + }, + "variables": [ + "{{variables.[Cloudflare Hyperdrive Config]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime", + "yAxisColumn": [ + "avg.currentPoolSize", + "avg.availablePoolSlots" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "c6bc4792-922b-4a02-a027-c5278bc00974", + "x": 2, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Waiting Clients", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[hyperdrivePoolSizes]}}", + "name": "hyperdrivePoolSizes", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Hyperdrive Configs]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Hyperdrive Config]}}" + }, + "variables": [ + "{{variables.[Cloudflare Hyperdrive Config]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime", + "yAxisColumn": [ + "avg.waitingClients", + "max.waitingClients" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } } ] } diff --git a/plugins/Cloudflare/v2/defaultContent/Storage & Databases/r2Bucket.dash.json b/plugins/Cloudflare/v2/defaultContent/Storage & Databases/r2Bucket.dash.json index d841eb4e..407b80cb 100644 --- a/plugins/Cloudflare/v2/defaultContent/Storage & Databases/r2Bucket.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Storage & Databases/r2Bucket.dash.json @@ -558,6 +558,62 @@ } } } + }, + { + "i": "ffdfeca3-954a-4f79-abbd-c89731c8d078", + "x": 0, + "y": 11, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Bandwidth", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[r2Bandwidth]}}", + "name": "r2Bandwidth", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare R2 Buckets]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare R2 Bucket]}}" + }, + "variables": [ + "{{variables.[Cloudflare R2 Bucket]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime", + "yAxisColumn": [ + "sum.bytesDownload", + "sum.bytesUpload" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } } ] } diff --git a/plugins/Cloudflare/v2/defaultContent/overview.dash.json b/plugins/Cloudflare/v2/defaultContent/overview.dash.json index ffc80611..c659bd74 100644 --- a/plugins/Cloudflare/v2/defaultContent/overview.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/overview.dash.json @@ -682,9 +682,216 @@ } }, { - "i": "01071810-2460-4d6f-ac37-2d8c6c78ace3", + "i": "ed93f0f7-9697-4096-b385-03cfcca256e8", "x": 0, "y": 10, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Requests by Zone", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accountTraffic]}}", + "name": "accountTraffic", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "zoneTag" + }, + "sort": { + "by": [ + [ + "datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}" + }, + "timeframe": "last24hours", + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "datetime", + "yAxisColumn": [ + "requests" + ], + "seriesColumn": "zoneName", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "f577bcf2-adb3-4fe5-b017-ecc1afe3c320", + "x": 0, + "y": 13, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Top Zones by Requests", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accountTraffic]}}", + "name": "accountTraffic", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "zoneTag" + }, + "group": { + "by": [ + [ + "zoneName", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "requests_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}" + }, + "timeframe": "last24hours", + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "zoneName_uniqueValues", + "yAxisData": [ + "requests_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "horizontal", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "468ed54a-6c84-4380-907b-8fce6d718637", + "x": 2, + "y": 13, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Bandwidth by Zone", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accountTraffic]}}", + "name": "accountTraffic", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "zoneTag" + }, + "group": { + "by": [ + [ + "zoneName", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "bytes" + ] + } + ] + }, + "sort": { + "by": [ + [ + "bytes_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}" + }, + "timeframe": "last24hours", + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "bytes_sum", + "labelColumn": "zoneName_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "01071810-2460-4d6f-ac37-2d8c6c78ace3", + "x": 0, + "y": 16, "w": 2, "h": 3, "moved": false, @@ -745,7 +952,7 @@ { "i": "06de4718-8250-4cc0-b864-1d9cc11c1394", "x": 2, - "y": 10, + "y": 16, "w": 2, "h": 3, "moved": false, @@ -806,7 +1013,7 @@ { "i": "6b70dcfc-f6fe-4f22-a57c-7fa7fa23be9c", "x": 0, - "y": 13, + "y": 19, "w": 4, "h": 3, "moved": false, @@ -857,7 +1064,7 @@ { "i": "2bbc6141-d374-41c7-93b1-3b3f7677c193", "x": 0, - "y": 16, + "y": 22, "w": 4, "h": 4, "moved": false, @@ -927,7 +1134,7 @@ { "i": "5be40674-431e-465f-94fc-3b658438dc77", "x": 0, - "y": 20, + "y": 26, "w": 2, "h": 3, "moved": false, @@ -978,7 +1185,7 @@ { "i": "f51e9fdc-9a9e-4272-b24d-9d5d11eac793", "x": 2, - "y": 20, + "y": 26, "w": 2, "h": 3, "moved": false, @@ -1029,7 +1236,7 @@ { "i": "f2587bfd-deef-45ac-9501-1d66bf9c7734", "x": 0, - "y": 23, + "y": 29, "w": 2, "h": 3, "moved": false, @@ -1080,7 +1287,7 @@ { "i": "af6eee0c-cfbf-43e1-a51c-53dca0e9a356", "x": 2, - "y": 23, + "y": 29, "w": 2, "h": 3, "moved": false, @@ -1130,7 +1337,7 @@ { "i": "9beee6df-b954-4c3f-9c99-dd09a66a3f6a", "x": 0, - "y": 26, + "y": 32, "w": 2, "h": 3, "moved": false, @@ -1181,7 +1388,7 @@ { "i": "c6e175b9-164a-4b14-a4a2-22312083c04f", "x": 2, - "y": 26, + "y": 32, "w": 2, "h": 3, "moved": false, @@ -1231,7 +1438,7 @@ { "i": "62ced3d6-e538-4573-af2c-24365a1d7b52", "x": 0, - "y": 29, + "y": 35, "w": 2, "h": 3, "moved": false, @@ -1281,7 +1488,7 @@ { "i": "4a7ce999-9bb4-48f9-890d-6d6dcb4d5e49", "x": 2, - "y": 29, + "y": 35, "w": 2, "h": 3, "moved": false, @@ -1331,7 +1538,7 @@ { "i": "0db6f61a-dc9f-499c-bd92-b863f2cc9eed", "x": 0, - "y": 32, + "y": 38, "w": 4, "h": 3, "moved": false, @@ -1382,7 +1589,7 @@ { "i": "2e3d6f85-4a2c-4429-b1cc-f1b1a7750964", "x": 0, - "y": 35, + "y": 41, "w": 2, "h": 3, "moved": false, @@ -1433,7 +1640,7 @@ { "i": "f8197c33-da9e-4c1f-91eb-03271dec641f", "x": 2, - "y": 35, + "y": 41, "w": 2, "h": 3, "moved": false, @@ -1484,7 +1691,7 @@ { "i": "6f46fa83-d107-4c9e-a103-bb10026a3f91", "x": 0, - "y": 38, + "y": 44, "w": 2, "h": 3, "moved": false, @@ -1535,7 +1742,7 @@ { "i": "7c07b110-f283-4502-a0fc-9d8790815b9c", "x": 2, - "y": 38, + "y": 44, "w": 2, "h": 3, "moved": false, @@ -1586,7 +1793,7 @@ { "i": "2115654f-a854-4c27-8231-e3d8dc3cd77c", "x": 0, - "y": 41, + "y": 47, "w": 4, "h": 3, "moved": false, @@ -1637,7 +1844,7 @@ { "i": "24cf5eb9-6bad-433f-a748-637d668a707b", "x": 0, - "y": 44, + "y": 50, "w": 2, "h": 3, "moved": false, @@ -1688,7 +1895,7 @@ { "i": "c4afc6e8-d873-439e-b23a-524115490249", "x": 2, - "y": 44, + "y": 50, "w": 2, "h": 3, "moved": false, @@ -1739,7 +1946,7 @@ { "i": "f1c1ad4a-931b-4987-a772-d8367090ef02", "x": 0, - "y": 47, + "y": 53, "w": 2, "h": 3, "moved": false, @@ -1789,7 +1996,7 @@ { "i": "ca16cfd0-c194-409b-94a6-4d4297c9254a", "x": 2, - "y": 47, + "y": 53, "w": 2, "h": 3, "moved": false, @@ -1840,7 +2047,7 @@ { "i": "2dc4925f-e310-48f8-aa1a-8cc5b80e52d4", "x": 0, - "y": 50, + "y": 56, "w": 2, "h": 3, "moved": false, @@ -1891,7 +2098,7 @@ { "i": "1ed1f8bb-409a-492e-a0fd-ca4a7682c558", "x": 2, - "y": 50, + "y": 56, "w": 2, "h": 3, "moved": false, @@ -1942,7 +2149,7 @@ { "i": "64731322-4823-4187-8d15-cfa52d8f0c58", "x": 0, - "y": 53, + "y": 59, "w": 4, "h": 3, "moved": false, diff --git a/plugins/Cloudflare/v2/docs/README.md b/plugins/Cloudflare/v2/docs/README.md index e9db9fd9..4c19eb7a 100644 --- a/plugins/Cloudflare/v2/docs/README.md +++ b/plugins/Cloudflare/v2/docs/README.md @@ -70,19 +70,28 @@ The out-of-the-box dashboards open with a **Cloudflare Overview**, with perspect - **Zone Traffic Breakdown** - requests, bytes and visits for a zone grouped by a dimension you choose (country, status code, cache status, host, device type, HTTP protocol or content type). - **Zone Firewall Events** - firewall and WAF event counts for a zone by action, grouped by rule, service, country, host, user agent or path. - **Zone Firewall Event Volume** - firewall and WAF event counts over time for a zone, optionally filtered by action and service, for up to 30 days on every plan. +- **Account Traffic** - requests, bandwidth and visits across every zone in an account in one query, grouped by zone, country, status code, cache status, host or device type. - **Load Balancing Requests** - load balancer request counts for a zone by load balancer, pool, origin and edge location. - **DNS Records** - every DNS record in a zone with type, content, TTL, proxy status and tags. - **SSL Certificates** - certificate packs for a zone with issuer, validation method, expiry date and days until expiry. - **Health Checks** - standalone health checks configured on a zone with status, address, interval and failure reason. - **Worker Invocations** - requests, errors, subrequests and CPU-time percentiles for one Worker script. +- **Worker Subrequests** - outbound requests a Worker makes, with bytes and P50/P99 response time, grouped by host, cache status, status code or outcome. +- **Worker Cron Trigger Runs** - each scheduled run of a Worker with its schedule, outcome and CPU time, so a failing cron trigger is visible. +- **Worker Static Asset Requests** - requests served from a Worker's static assets, by status code, cache status or host. +- **Worker Cache Requests** - Cache API requests a Worker makes, by cache status. +- **Worker Smart Placement** - requests and duration for a Worker, split by whether Smart Placement ran it near its back end. +- **Workers Build Minutes** - Workers Builds minutes used by an account. - **R2 Operations** - requests and response bytes against an R2 bucket by operation type and outcome. - **R2 Storage** - stored object count, payload size, metadata size and upload count for an R2 bucket over time. +- **R2 Bandwidth** - bytes downloaded from and uploaded to an R2 bucket. - **KV Operations** - request counts and latency percentiles for a KV namespace by operation type. - **KV Storage** - stored key count and byte size for a KV namespace. - **D1 Queries** - read and write query counts, rows read and written, response bytes and query-time percentiles for a D1 database. - **D1 Storage** - stored size of a D1 database. - **Queue Message Operations** - message write, read and delete operations on a queue with outcome, consumer type, lag time and retry count. - **Queue Backlog** - average messages and bytes waiting in a queue over time. +- **Queue Delayed Backlog** - average delayed messages waiting in a queue. - **Pages Deployments** - deployment history for a Pages project with environment, status, branch, commit and URL. - **Tunnel Connections** - active connector connections for a Tunnel with edge location, origin IP, connector version and architecture. - **Load Balancer Pool Health** - per-origin health, response code, response time and failure reason for a pool at each Cloudflare edge location. @@ -97,6 +106,7 @@ The out-of-the-box dashboards open with a **Cloudflare Overview**, with perspect - **Page Shield Reports** - client-side scripts and resources observed on a zone. - **Web Analytics Page Loads** - page views and visits for a zone's hostnames, grouped by country, device type or referrer. - **Core Web Vitals** - P75 Largest Contentful Paint, Interaction to Next Paint and Cumulative Layout Shift for a zone's hostnames. +- **Web Analytics Page Load Timing** - P75 DNS, connection, request, response, first contentful paint and page load times for a zone's hostnames. - **Gateway DNS Queries** - Zero Trust Gateway DNS resolutions for an account by policy decision, category, location or query type. - **Gateway HTTP Requests** - Zero Trust Gateway proxied web requests for an account by action, host or category. - **Gateway Network Sessions** - Zero Trust Gateway TCP and UDP sessions for an account by action, destination, protocol or device. @@ -106,6 +116,7 @@ The out-of-the-box dashboards open with a **Cloudflare Overview**, with perspect - **Vectorize Queries** - query volume and average latency for a Vectorize index. - **Vectorize Storage** - stored vector count and dimensions for a Vectorize index. - **Hyperdrive Queries** - query volume and average latency for a Hyperdrive configuration. +- **Hyperdrive Connection Pool** - pool size, free slots and waiting clients for a Hyperdrive configuration. - **Gateway Network Sessions** - Zero Trust Gateway TCP and UDP sessions for an account by action, destination, protocol or device. - **DNS Firewall Analytics** - DNS Firewall cluster query volume, response codes and processing time for an account. - **Audit Logs** - account audit activity grouped by action, actor or resource type. @@ -125,6 +136,7 @@ The out-of-the-box dashboards open with a **Cloudflare Overview**, with perspect - **Pipeline Ingestion** - records and bytes ingested by a pipeline. - **Queue Consumer Metrics** - average consumer concurrency for a queue. - **Durable Object Subrequests** - uncached subrequest body size for a Durable Object namespace. +- **Durable Object Activity** - active time, CPU time, storage operations, limit errors, peak memory and WebSocket connections for a Durable Object namespace. - **D1 Query Insights** - query counts, rows touched and query duration percentiles for a D1 database. - **GraphQL Query** - runs any query you write against Cloudflare's GraphQL Analytics API, for the many datasets this plugin has no dedicated stream for. @@ -201,13 +213,13 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w | **1 day / 3 days** on Pro; none on Free | Zone Firewall Events | Last 24 hours (Last 7 and 30 days on higher plans - see below) | | **30 days / 31 days** on every plan | Zone Firewall Event Volume | Last 30 days | | **3 days / 3 days** | Health Check Events, Load Balancing Requests | Last 24 hours | - | **7 days** | Access Logins, Network Error Logs, Page Shield Reports | Last 7 days | + | **7 days** | Access Logins, Network Error Logs, Page Shield Reports, Worker Cron Trigger Runs | Last 7 days | | **7 days** on Free; **30 days** on Enterprise | Turnstile Challenges | Last 7 days (Last 30 days on Enterprise Turnstile) | | **30-31 days / 31 days** | Gateway HTTP Requests and Network Sessions, Stream Playback Quality, DNS Analytics, Zone Traffic Breakdown | Last 30 days | - | **31-32 days / 31-32 days** | Gateway DNS Queries, Email Routing, DMARC Reports, Images Requests, AI Gateway Cache and Errors, AutoRAG, Browser Rendering, Container Metrics, Hyperdrive, Queue Consumer Metrics, Realtime Usage, Vectorize, Workers AI | This month | - | **32-62 days / 62-92 days** | Worker Invocations, Pages Functions, KV, D1, R2, Durable Objects, Queue Backlog and Message Operations, Pipeline Ingestion, Cache Reserve, AI Gateway Requests, DNS Firewall Analytics, Stream Minutes Viewed | Last month | + | **31-32 days / 31-32 days** | Gateway DNS Queries, Email Routing, DMARC Reports, Images Requests, AI Gateway Cache and Errors, AutoRAG, Browser Rendering, Container Metrics, Hyperdrive, Queue Consumer Metrics, Realtime Usage, Vectorize, Workers AI, Account Traffic, Worker Static Asset Requests, Worker Smart Placement, Workers Build Minutes, Hyperdrive Connection Pool, R2 Bandwidth | This month | + | **32-62 days / 62-92 days** | Worker Invocations, Pages Functions, KV, D1, R2, Durable Objects, Queue Backlog and Message Operations, Pipeline Ingestion, Cache Reserve, AI Gateway Requests, DNS Firewall Analytics, Stream Minutes Viewed, Worker Subrequests, Worker Cache Requests, Queue Delayed Backlog, Durable Object Activity | Last month | | **61 days, daily only** | Images Unique Transformations | This month | - | **93 days / 184 days** | Web Analytics Page Loads, Core Web Vitals | This quarter | + | **93 days / 184 days** | Web Analytics Page Loads, Core Web Vitals, Web Analytics Page Load Timing | This quarter | | **180 days / 540 days** | Audit Logs | Last quarter | | **365 days, daily** | Zone Traffic (hourly up to two days, then daily) | This year | @@ -243,12 +255,13 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w - **Load balancing analytics is gated per zone**, not per account. Zones without the Load Balancing add-on return an authorization error rather than empty data. - **Pages endpoints cap page size at 10.** Cloudflare rejects any larger `per_page` on the Pages API, so Pages projects and deployments are fetched ten at a time. - **Some resource lists are not paged.** R2 buckets, D1 databases, Queues, load balancer pools, Access applications, Vectorize indexes, Hyperdrive configs, Worker scripts and Worker routes are imported in a single request each. Where Cloudflare's paging behaviour could be proven against real data it is used (zones, accounts, DNS records, Pages projects, KV namespaces, Tunnels and Durable Object namespaces all page); the rest were left unpaged because the endpoint either ignores the paging parameters outright — as `workers/scripts` does — or holds too few records in the tested account to confirm they are honoured. If an account holds more of one of these than Cloudflare returns on a single page, the remainder is not imported. -- **Rate limits.** The REST API allowed 1,200 requests per 300 seconds on the token tested, and Cloudflare documents a separate limit of 300 GraphQL queries per 5 minutes. Every analytics stream issues one request per selected object, so very large estates can hit these limits. +- **Rate limits.** The REST API allowed 1,200 requests per 300 seconds on the token tested. GraphQL queries are by default limited to 300 per 5 minutes per token, so the analytics streams opt into Cloudflare's [account-based rate limiting](https://developers.cloudflare.com/analytics/graphql-api/account-based-rate-limiting/), which gives each account and each zone its own 300-per-5-minutes budget instead. Every analytics stream issues one request per selected object, so a tile scoped to hundreds of objects can still reach a per-account limit. The **GraphQL Query** stream keeps the per-token limit, because account-based limiting does not support queries that list several zones at the top level. - **A breakdown with very many values is truncated.** Cloudflare caps a GraphQL result at 10,000 rows (5,000 on some streams here). The time buckets above keep time-series streams well inside it, but a breakdown such as DNS Analytics by query name on a busy zone can still exceed it. Those streams order by count, so the rows dropped are the least frequent values rather than the most recent part of the range. - **Hand-written GraphQL queries are unbounded.** The **GraphQL Query** stream runs whatever you give it, so it can hit limits the built-in streams are tuned to avoid: a large `limit` on a multi-dimension dataset can exceed the ~6 MB response cap, and a timeframe wider than that dataset's own cap fails with Cloudflare's error naming the limit. Prefer the pre-aggregated `*Groups` datasets over raw event datasets, and keep `limit` modest. The stream does not page, so your `limit` is the ceiling. -- **Some analytics are only available on paid plans.** Page Shield and Network Error Logs return an authorization error on plans without them; Cache Reserve, Load Balancing and Health Checks are add-ons. An unentitled feature shows no data rather than an error in most tiles. -- **A failed Cloudflare query can look like "no data".** Cloudflare answers a failed GraphQL query with HTTP 200 and an `errors` array, which the platform does not treat as a failure. Streams that use a post-request script raise these errors explicitly, but the simpler declarative streams will show an empty tile instead of an error message. +- **Some analytics are only available on paid plans.** Page Shield and Network Error Logs return an authorization error on plans without them; Cache Reserve, Load Balancing and Health Checks are add-ons. A tile for a feature the zone or account is not entitled to shows Cloudflare's authorization error rather than empty data. +- **Account Traffic shows zones it cannot name by their zone tag.** The stream resolves each zone tag to an imported zone's name. Traffic for a zone the token cannot list - for example one outside the token's zone resources - appears as *Object not found: Cloudflare Zone/<tag>*. +- **Tunnel bandwidth is not available.** Cloudflare exposes `cloudflared` traffic metrics from each connector's local metrics endpoint rather than through the API, so Tunnels show connector health only. - **Costs are unitless.** Cloudflare's AI Gateway analytics reports cost without stating a currency, so the plugin shows a plain number rather than assuming one. - **Pages Functions cannot be scoped to a single project.** Cloudflare identifies Pages Functions by an internal script name with no published mapping to the project, so this stream reports all Pages Functions in the account, with the function name as a column. - **The first import only populates accounts and zones.** Everything below them - Workers, KV namespaces, queues, tunnels, Stream videos, Turnstile widgets and the rest - is imported by steps that run against the accounts and zones the same import has just created, and on a brand new data source those objects are not yet visible when those steps start. They are skipped with a warning, and the **next import picks them all up**. Trigger a re-import from the data source page after adding the plugin rather than waiting for the scheduled one. From 9201d57afa7a47fed65d8b80b4c37cb0002ede3d Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Nov 2026 23:47:22 +0000 Subject: [PATCH 18/27] Send the rate-limit header from base config and simplify GraphQL Query - Move X-Rate-Limit-Type: account-based from 65 data streams into the data source's base headers. Data sources created before this change do not pick it up and need re-adding. The GraphQL Query stream's queries, including a viewer-level zone list, were tested with the header. - GraphQL Query: an optional Zone or account picker fills $zoneTag, $zoneTags and $accountTag, so queries no longer need IDs pasted into Variables, and a bound dashboard variable makes one tile serve every zone. Path to rows is now optional and defaults to the first array of rows in the response. The default query filters on the selected zone, with a clear message when none is selected. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01FsDuPXY2CFtKbw4Cxn6cRF --- .../v2/dataStreams/accessLogins.json | 1 - .../v2/dataStreams/accountTraffic.json | 6 ---- .../v2/dataStreams/aiGatewayCache.json | 1 - .../v2/dataStreams/aiGatewayErrors.json | 1 - .../v2/dataStreams/aiGatewayRequests.json | 1 - .../Cloudflare/v2/dataStreams/auditLogs.json | 1 - .../v2/dataStreams/autoragQueries.json | 1 - .../v2/dataStreams/browserRendering.json | 1 - .../dataStreams/cacheReserveOperations.json | 1 - .../v2/dataStreams/cacheReserveStorage.json | 1 - .../v2/dataStreams/containerMetrics.json | 1 - .../v2/dataStreams/d1Analytics.json | 1 - .../Cloudflare/v2/dataStreams/d1Queries.json | 1 - .../Cloudflare/v2/dataStreams/d1Storage.json | 1 - .../v2/dataStreams/dmarcReports.json | 1 - .../v2/dataStreams/dnsFirewallAnalytics.json | 1 - .../v2/dataStreams/durableObjectActivity.json | 6 ---- .../dataStreams/durableObjectInvocations.json | 1 - .../v2/dataStreams/durableObjectStorage.json | 1 - .../dataStreams/durableObjectSubrequests.json | 1 - .../v2/dataStreams/emailRouting.json | 1 - .../v2/dataStreams/gatewayDnsQueries.json | 1 - .../v2/dataStreams/gatewayHttpRequests.json | 1 - .../dataStreams/gatewayNetworkSessions.json | 1 - .../v2/dataStreams/graphqlQuery.json | 32 ++++++++++++------- .../v2/dataStreams/hyperdrivePoolSizes.json | 6 ---- .../v2/dataStreams/hyperdriveQueries.json | 1 - .../v2/dataStreams/imagesRequests.json | 1 - .../v2/dataStreams/imagesTransformations.json | 1 - .../v2/dataStreams/kvOperations.json | 1 - .../Cloudflare/v2/dataStreams/kvStorage.json | 1 - .../pagesFunctionsInvocations.json | 1 - .../v2/dataStreams/pipelineIngestion.json | 1 - .../v2/dataStreams/queueBacklog.json | 1 - .../v2/dataStreams/queueConsumerMetrics.json | 1 - .../v2/dataStreams/queueDelayedBacklog.json | 6 ---- .../dataStreams/queueMessageOperations.json | 1 - .../v2/dataStreams/r2Bandwidth.json | 6 ---- .../v2/dataStreams/r2Operations.json | 1 - .../Cloudflare/v2/dataStreams/r2Storage.json | 1 - .../v2/dataStreams/realtimeUsage.json | 1 - .../v2/dataStreams/rumPageLoadTiming.json | 6 ---- .../v2/dataStreams/rumPageLoads.json | 1 - .../v2/dataStreams/rumWebVitals.json | 1 - .../v2/dataStreams/scripts/graphqlQuery.js | 30 +++++++++++++---- .../Cloudflare/v2/dataStreams/streamCmcd.json | 1 - .../v2/dataStreams/streamMinutesViewed.json | 1 - .../v2/dataStreams/turnstileChallenges.json | 1 - .../v2/dataStreams/vectorizeQueries.json | 1 - .../v2/dataStreams/vectorizeStorage.json | 1 - .../v2/dataStreams/workerBuildMinutes.json | 6 ---- .../v2/dataStreams/workerCacheRequests.json | 6 ---- .../v2/dataStreams/workerCronRuns.json | 6 ---- .../v2/dataStreams/workerInvocations.json | 1 - .../v2/dataStreams/workerSmartPlacement.json | 6 ---- .../v2/dataStreams/workerStaticAssets.json | 6 ---- .../v2/dataStreams/workerSubrequests.json | 6 ---- .../v2/dataStreams/workersAiInference.json | 1 - .../v2/dataStreams/zoneDnsAnalytics.json | 1 - .../dataStreams/zoneFirewallEventVolume.json | 1 - .../v2/dataStreams/zoneFirewallEvents.json | 1 - .../v2/dataStreams/zoneHealthCheckEvents.json | 1 - .../v2/dataStreams/zoneLoadBalancing.json | 1 - .../v2/dataStreams/zoneNelReports.json | 1 - .../v2/dataStreams/zonePageShield.json | 1 - .../v2/dataStreams/zoneTraffic.json | 1 - .../v2/dataStreams/zoneTrafficBreakdown.json | 1 - plugins/Cloudflare/v2/docs/README.md | 16 ++++++---- plugins/Cloudflare/v2/metadata.json | 4 +++ 69 files changed, 59 insertions(+), 148 deletions(-) diff --git a/plugins/Cloudflare/v2/dataStreams/accessLogins.json b/plugins/Cloudflare/v2/dataStreams/accessLogins.json index c7948608..94049b5e 100644 --- a/plugins/Cloudflare/v2/dataStreams/accessLogins.json +++ b/plugins/Cloudflare/v2/dataStreams/accessLogins.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$appId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){accessLoginRequestsAdaptiveGroups(limit:10000,filter:{appId:$appId,datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} identityProvider isSuccessfulLogin country hasWarpEnabled}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/accountTraffic.json b/plugins/Cloudflare/v2/dataStreams/accountTraffic.json index b850b355..b7745127 100644 --- a/plugins/Cloudflare/v2/dataStreams/accountTraffic.json +++ b/plugins/Cloudflare/v2/dataStreams/accountTraffic.json @@ -9,12 +9,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [ - { - "key": "X-Rate-Limit-Type", - "value": "account-based" - } - ], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){httpRequestsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count sum{edgeResponseBytes visits} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown || 'zoneTag'}} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/aiGatewayCache.json b/plugins/Cloudflare/v2/dataStreams/aiGatewayCache.json index 6849ebae..e3078146 100644 --- a/plugins/Cloudflare/v2/dataStreams/aiGatewayCache.json +++ b/plugins/Cloudflare/v2/dataStreams/aiGatewayCache.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$gateway:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiGatewayCacheAdaptiveGroups(limit:10000,filter:{gateway:$gateway,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} cacheOp}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/aiGatewayErrors.json b/plugins/Cloudflare/v2/dataStreams/aiGatewayErrors.json index 19bdd8ae..927643ae 100644 --- a/plugins/Cloudflare/v2/dataStreams/aiGatewayErrors.json +++ b/plugins/Cloudflare/v2/dataStreams/aiGatewayErrors.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$gateway:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiGatewayErrorsAdaptiveGroups(limit:10000,filter:{gateway:$gateway,datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/aiGatewayRequests.json b/plugins/Cloudflare/v2/dataStreams/aiGatewayRequests.json index c60e9461..7a8c1438 100644 --- a/plugins/Cloudflare/v2/dataStreams/aiGatewayRequests.json +++ b/plugins/Cloudflare/v2/dataStreams/aiGatewayRequests.json @@ -10,7 +10,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$gateway:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiGatewayRequestsAdaptiveGroups(limit:10000,filter:{gateway:$gateway,datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}} sum{cost tokensIn tokensOut totalTokens cachedRequests erroredRequests} quantiles{durationMsP50 durationMsP95}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/auditLogs.json b/plugins/Cloudflare/v2/dataStreams/auditLogs.json index ea886763..d9d297f5 100644 --- a/plugins/Cloudflare/v2/dataStreams/auditLogs.json +++ b/plugins/Cloudflare/v2/dataStreams/auditLogs.json @@ -10,7 +10,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){auditLogsGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/autoragQueries.json b/plugins/Cloudflare/v2/dataStreams/autoragQueries.json index 1f6a373e..42de5335 100644 --- a/plugins/Cloudflare/v2/dataStreams/autoragQueries.json +++ b/plugins/Cloudflare/v2/dataStreams/autoragQueries.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$instanceId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiSearchAPIAdaptiveGroups(limit:10000,filter:{instanceId:$instanceId,datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count sum{aiSearchCount searchCount} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/browserRendering.json b/plugins/Cloudflare/v2/dataStreams/browserRendering.json index 2f6b1b8e..5f27872a 100644 --- a/plugins/Cloudflare/v2/dataStreams/browserRendering.json +++ b/plugins/Cloudflare/v2/dataStreams/browserRendering.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){browserRenderingEventsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count avg{avgConcurrentSessions} min{earliestBrowserStartTime} max{latestBrowserEndTime} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} sessionId {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json b/plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json index 19385ef5..f426006f 100644 --- a/plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json +++ b/plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){cacheReserveOperationsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){sum{requests}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/cacheReserveStorage.json b/plugins/Cloudflare/v2/dataStreams/cacheReserveStorage.json index 9f49f627..a85dbd36 100644 --- a/plugins/Cloudflare/v2/dataStreams/cacheReserveStorage.json +++ b/plugins/Cloudflare/v2/dataStreams/cacheReserveStorage.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){cacheReserveStorageAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){max{objectCount storedBytes}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/containerMetrics.json b/plugins/Cloudflare/v2/dataStreams/containerMetrics.json index 441ceff8..1315eb59 100644 --- a/plugins/Cloudflare/v2/dataStreams/containerMetrics.json +++ b/plugins/Cloudflare/v2/dataStreams/containerMetrics.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$applicationId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){containersMetricsAdaptiveGroups(limit:10000,filter:{applicationId:$applicationId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){count avg{cpuUtilization memory containerUptime} sum{rxBytes txBytes} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/d1Analytics.json b/plugins/Cloudflare/v2/dataStreams/d1Analytics.json index fb59f2ed..357801b2 100644 --- a/plugins/Cloudflare/v2/dataStreams/d1Analytics.json +++ b/plugins/Cloudflare/v2/dataStreams/d1Analytics.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$databaseId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){d1AnalyticsAdaptiveGroups(limit:10000,filter:{databaseId:$databaseId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{readQueries writeQueries rowsRead rowsWritten queryBatchResponseBytes}quantiles{queryBatchTimeMsP50 queryBatchTimeMsP90 queryBatchTimeMsP99}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/d1Queries.json b/plugins/Cloudflare/v2/dataStreams/d1Queries.json index 52137fd9..fd592a7a 100644 --- a/plugins/Cloudflare/v2/dataStreams/d1Queries.json +++ b/plugins/Cloudflare/v2/dataStreams/d1Queries.json @@ -10,7 +10,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$databaseId:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){d1QueriesAdaptiveGroups(limit:10000,filter:{databaseId:$databaseId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){count sum{rowsRead rowsWritten rowsReturned}quantiles{queryDurationMsP50 queryDurationMsP95 queryDurationMsP99}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} databaseRole}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/d1Storage.json b/plugins/Cloudflare/v2/dataStreams/d1Storage.json index bcc13a18..670c3ba9 100644 --- a/plugins/Cloudflare/v2/dataStreams/d1Storage.json +++ b/plugins/Cloudflare/v2/dataStreams/d1Storage.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$databaseId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){d1StorageAdaptiveGroups(limit:10000,filter:{databaseId:$databaseId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){max{databaseSizeBytes}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/dmarcReports.json b/plugins/Cloudflare/v2/dataStreams/dmarcReports.json index ef23c157..c108d4be 100644 --- a/plugins/Cloudflare/v2/dataStreams/dmarcReports.json +++ b/plugins/Cloudflare/v2/dataStreams/dmarcReports.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){dmarcReportsSourcesAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[sum_totalMatchingMessages_DESC]){sum{totalMatchingMessages dmarc} avg{dmarc} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json b/plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json index ae50ecb2..9afa20fe 100644 --- a/plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json +++ b/plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){dnsFirewallAnalyticsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count quantiles{processingTimeUsP50} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/durableObjectActivity.json b/plugins/Cloudflare/v2/dataStreams/durableObjectActivity.json index 97b506d7..c97a2d04 100644 --- a/plugins/Cloudflare/v2/dataStreams/durableObjectActivity.json +++ b/plugins/Cloudflare/v2/dataStreams/durableObjectActivity.json @@ -10,12 +10,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [ - { - "key": "X-Rate-Limit-Type", - "value": "account-based" - } - ], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!,$namespaceId:string!){viewer{accounts(filter:{accountTag:$accountTag}){durableObjectsPeriodicGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{activeTime cpuTime rowsRead rowsWritten storageReadUnits storageWriteUnits subrequests exceededCpuErrors exceededMemoryErrors fatalInternalErrors} max{activeWebsocketConnections memoryUsageBytes} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/durableObjectInvocations.json b/plugins/Cloudflare/v2/dataStreams/durableObjectInvocations.json index 9c508489..a613736b 100644 --- a/plugins/Cloudflare/v2/dataStreams/durableObjectInvocations.json +++ b/plugins/Cloudflare/v2/dataStreams/durableObjectInvocations.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$namespaceId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){durableObjectsInvocationsAdaptiveGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{requests errors responseBodySize wallTime}quantiles{wallTimeP50 wallTimeP90 wallTimeP99}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} status}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/durableObjectStorage.json b/plugins/Cloudflare/v2/dataStreams/durableObjectStorage.json index 43d77f9b..565a30a5 100644 --- a/plugins/Cloudflare/v2/dataStreams/durableObjectStorage.json +++ b/plugins/Cloudflare/v2/dataStreams/durableObjectStorage.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$namespaceId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){durableObjectsSqlStorageGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){max{storedBytes}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/durableObjectSubrequests.json b/plugins/Cloudflare/v2/dataStreams/durableObjectSubrequests.json index c2b5629c..3ca5dc96 100644 --- a/plugins/Cloudflare/v2/dataStreams/durableObjectSubrequests.json +++ b/plugins/Cloudflare/v2/dataStreams/durableObjectSubrequests.json @@ -10,7 +10,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$namespaceId:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){durableObjectsSubrequestsAdaptiveGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{requestBodySizeUncached}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/emailRouting.json b/plugins/Cloudflare/v2/dataStreams/emailRouting.json index 60adb9fd..efa3e1c0 100644 --- a/plugins/Cloudflare/v2/dataStreams/emailRouting.json +++ b/plugins/Cloudflare/v2/dataStreams/emailRouting.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){emailRoutingAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json b/plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json index c9d4b986..37138fc9 100644 --- a/plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json +++ b/plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayResolverQueriesAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json b/plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json index 5817cf64..d031cb08 100644 --- a/plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json +++ b/plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayL7RequestsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json b/plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json index 01ce6953..ac97695d 100644 --- a/plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json +++ b/plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayL4SessionsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/graphqlQuery.json b/plugins/Cloudflare/v2/dataStreams/graphqlQuery.json index 6b25a54a..a73863a2 100644 --- a/plugins/Cloudflare/v2/dataStreams/graphqlQuery.json +++ b/plugins/Cloudflare/v2/dataStreams/graphqlQuery.json @@ -1,7 +1,7 @@ { "name": "graphqlQuery", "displayName": "GraphQL Query", - "description": "Rows returned by a user-supplied Cloudflare GraphQL Analytics query", + "description": "Rows returned by a Cloudflare GraphQL Analytics query you write, optionally for a chosen zone or account", "tags": [ "Analytics" ], @@ -12,7 +12,7 @@ "endpointPath": "graphql", "postBody": { "query": "{{query}}", - "variables": "{{ Object.assign(typeof timeframe !== 'undefined' && timeframe && timeframe.start ? { start: timeframe.start, end: timeframe.end, startDate: timeframe.start.split('T')[0], endDate: timeframe.end.split('T')[0] } : {}, typeof variables === 'string' ? JSON.parse(variables || '{}') : (variables || {})) }}" + "variables": "{{ ((u) => { const picked = typeof target !== 'undefined' && Array.isArray(target) ? target : []; const zones = picked.filter((o) => u(o.sourceType) === 'Cloudflare Zone'); const account = picked.find((o) => u(o.sourceType) === 'Cloudflare Account'); const fromTarget = {}; if (zones.length) { fromTarget.zoneTag = u(zones[0].rawId); fromTarget.zoneTags = zones.map((o) => u(o.rawId)); fromTarget.accountTag = u(zones[0].accountId); } if (account) fromTarget.accountTag = u(account.rawId); const fromTimeframe = typeof timeframe !== 'undefined' && timeframe && timeframe.start ? { start: timeframe.start, end: timeframe.end, startDate: timeframe.start.split('T')[0], endDate: timeframe.end.split('T')[0] } : {}; const own = typeof variables === 'string' ? JSON.parse(variables || '{}') : variables || {}; return Object.assign(fromTimeframe, fromTarget, own); })(((v) => (Array.isArray(v) ? v[0] : v))) }}" }, "postRequestScript": "graphqlQuery.js", "errorHandling": { @@ -23,13 +23,27 @@ }, "matches": "none", "ui": [ + { + "type": "objects", + "name": "target", + "label": "Zone or account (optional)", + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Zone", + "Cloudflare Account" + ] + } + } + }, { "type": "code", "name": "query", "label": "GraphQL query", "language": "graphql", - "help": "A query for the Cloudflare GraphQL Analytics API. These variables are always sent and can be declared in the query: `$start` / `$end` (`Time!`, ISO 8601, the selected timeframe) and `$startDate` / `$endDate` (`Date!`, `YYYY-MM-DD`). Cloudflare's scalar names are case sensitive - `string!` is lower case, `Time!` and `Date!` are not. Each analytics node has its own maximum query window and retention, which vary by Cloudflare plan (as little as 1 day on some nodes) - a wider timeframe fails with Cloudflare's error naming the limit. For a fixed window, select the **None** timeframe and write the dates into the query's own filter. See the [Cloudflare GraphQL Analytics docs](https://developers.cloudflare.com/analytics/graphql-api/).", - "defaultValue": "query ($start: Time!, $end: Time!) {\n viewer {\n zones(limit: 1) {\n httpRequests1hGroups(\n limit: 1000\n filter: { datetime_geq: $start, datetime_leq: $end }\n orderBy: [datetime_ASC]\n ) {\n dimensions {\n datetime\n }\n sum {\n requests\n bytes\n cachedRequests\n threats\n }\n uniq {\n uniques\n }\n }\n }\n }\n}", + "help": "Declare any of these variables to use them: `$start` / `$end` (`Time!`) and `$startDate` / `$endDate` (`Date!`) from the timeframe, and `$zoneTag`, `$zoneTags` (`[string!]`) and `$accountTag` (`string`) from the selected zone or account. Each dataset limits how wide a timeframe it accepts; a wider one fails with the limit named. See the [GraphQL Analytics docs](https://developers.cloudflare.com/analytics/graphql-api/).", + "defaultValue": "query ($zoneTag: string, $start: Time!, $end: Time!) {\n viewer {\n zones(filter: { zoneTag: $zoneTag }, limit: 1) {\n httpRequests1hGroups(\n limit: 1000\n filter: { datetime_geq: $start, datetime_leq: $end }\n orderBy: [datetime_ASC]\n ) {\n dimensions {\n datetime\n }\n sum {\n requests\n bytes\n cachedRequests\n threats\n }\n uniq {\n uniques\n }\n }\n }\n }\n}", "validation": { "required": true } @@ -39,19 +53,15 @@ "name": "variables", "label": "Variables", "language": "json", - "help": "Extra GraphQL variables as a JSON object, for example `{ \"zoneTag\": \"\" }` or `{ \"accountTag\": \"\" }`. These are merged with the built-in `start`, `end`, `startDate` and `endDate` variables; a value set here of the same name wins.", + "help": "Extra variables as a JSON object, for example `{ \"limit\": 50 }`. A value here overrides the built-in variable of the same name.", "defaultValue": {} }, { "type": "text", "name": "pathToData", "label": "Path to rows", - "placeholder": "data.viewer.zones.0.httpRequests1hGroups", - "help": "Dot path to the array of rows in the query response, for example `data.viewer.zones.0.httpRequests1hGroups`. Nested fields in each row become dot-notation columns such as `sum.requests`. If the path is wrong, the error lists the array paths the response actually contains.", - "defaultValue": "data.viewer.zones.0.httpRequests1hGroups", - "validation": { - "required": true - } + "placeholder": "Automatic", + "help": "Leave empty to use the first array of rows in the response. Set a dot path, such as `data.viewer.zones.0.httpRequests1hGroups`, when the query reads several datasets or zones." } ], "metadata": [ diff --git a/plugins/Cloudflare/v2/dataStreams/hyperdrivePoolSizes.json b/plugins/Cloudflare/v2/dataStreams/hyperdrivePoolSizes.json index e25c24b6..626f57dd 100644 --- a/plugins/Cloudflare/v2/dataStreams/hyperdrivePoolSizes.json +++ b/plugins/Cloudflare/v2/dataStreams/hyperdrivePoolSizes.json @@ -10,12 +10,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [ - { - "key": "X-Rate-Limit-Type", - "value": "account-based" - } - ], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!,$configId:string!){viewer{accounts(filter:{accountTag:$accountTag}){hyperdrivePoolSizesAdaptiveGroups(limit:10000,filter:{configId:$configId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){avg{currentPoolSize availablePoolSlots waitingClients} max{maxPoolSize waitingClients} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/hyperdriveQueries.json b/plugins/Cloudflare/v2/dataStreams/hyperdriveQueries.json index 332f9683..3b16ec48 100644 --- a/plugins/Cloudflare/v2/dataStreams/hyperdriveQueries.json +++ b/plugins/Cloudflare/v2/dataStreams/hyperdriveQueries.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$configId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){hyperdriveQueriesAdaptiveGroups(limit:10000,filter:{configId:$configId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count avg{queryLatency} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/imagesRequests.json b/plugins/Cloudflare/v2/dataStreams/imagesRequests.json index 5241f527..82223801 100644 --- a/plugins/Cloudflare/v2/dataStreams/imagesRequests.json +++ b/plugins/Cloudflare/v2/dataStreams/imagesRequests.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){imagesRequestsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){sum{requests}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/imagesTransformations.json b/plugins/Cloudflare/v2/dataStreams/imagesTransformations.json index 5d140f75..aeee4a94 100644 --- a/plugins/Cloudflare/v2/dataStreams/imagesTransformations.json +++ b/plugins/Cloudflare/v2/dataStreams/imagesTransformations.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Date,$end:Date){viewer{accounts(filter:{accountTag:$accountTag}){imagesUniqueTransformations(limit:10000,filter:{date_geq:$start,date_leq:$end},orderBy:[date_ASC]){date transformations}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/kvOperations.json b/plugins/Cloudflare/v2/dataStreams/kvOperations.json index a57dfd2a..33d141a7 100644 --- a/plugins/Cloudflare/v2/dataStreams/kvOperations.json +++ b/plugins/Cloudflare/v2/dataStreams/kvOperations.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$namespaceId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){kvOperationsAdaptiveGroups(limit:10000,filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_DESC]){sum{requests}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} actionType}quantiles{latencyMsP50 latencyMsP90 latencyMsP99}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/kvStorage.json b/plugins/Cloudflare/v2/dataStreams/kvStorage.json index 9bb90fc7..f623e7fa 100644 --- a/plugins/Cloudflare/v2/dataStreams/kvStorage.json +++ b/plugins/Cloudflare/v2/dataStreams/kvStorage.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$namespaceId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){kvStorageAdaptiveGroups(filter:{namespaceId:$namespaceId,datetime_geq:$start,datetime_leq:$end},limit:10000,orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_DESC]){max{keyCount byteCount}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/pagesFunctionsInvocations.json b/plugins/Cloudflare/v2/dataStreams/pagesFunctionsInvocations.json index c41adbfa..a22d63a1 100644 --- a/plugins/Cloudflare/v2/dataStreams/pagesFunctionsInvocations.json +++ b/plugins/Cloudflare/v2/dataStreams/pagesFunctionsInvocations.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){pagesFunctionsInvocationsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{requests errors subrequests}quantiles{cpuTimeP50 cpuTimeP99}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} scriptName status}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/pipelineIngestion.json b/plugins/Cloudflare/v2/dataStreams/pipelineIngestion.json index 87129805..7f40a8d7 100644 --- a/plugins/Cloudflare/v2/dataStreams/pipelineIngestion.json +++ b/plugins/Cloudflare/v2/dataStreams/pipelineIngestion.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$pipelineId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){pipelinesIngestionAdaptiveGroups(limit:10000,filter:{pipelineId:$pipelineId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count sum{ingestedBytes ingestedRecords} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/queueBacklog.json b/plugins/Cloudflare/v2/dataStreams/queueBacklog.json index 786d4095..9ee00876 100644 --- a/plugins/Cloudflare/v2/dataStreams/queueBacklog.json +++ b/plugins/Cloudflare/v2/dataStreams/queueBacklog.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$queueId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){queueBacklogAdaptiveGroups(limit:10000,filter:{queueId:$queueId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){avg{messages bytes}dimensions{datetimeHour: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/queueConsumerMetrics.json b/plugins/Cloudflare/v2/dataStreams/queueConsumerMetrics.json index e1c87fc0..2a115319 100644 --- a/plugins/Cloudflare/v2/dataStreams/queueConsumerMetrics.json +++ b/plugins/Cloudflare/v2/dataStreams/queueConsumerMetrics.json @@ -10,7 +10,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$queueId:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){queueConsumerMetricsAdaptiveGroups(limit:10000,filter:{queueId:$queueId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){avg{concurrency}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/queueDelayedBacklog.json b/plugins/Cloudflare/v2/dataStreams/queueDelayedBacklog.json index 0b80af9e..081e2dc7 100644 --- a/plugins/Cloudflare/v2/dataStreams/queueDelayedBacklog.json +++ b/plugins/Cloudflare/v2/dataStreams/queueDelayedBacklog.json @@ -10,12 +10,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [ - { - "key": "X-Rate-Limit-Type", - "value": "account-based" - } - ], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!,$queueId:string!){viewer{accounts(filter:{accountTag:$accountTag}){queueDelayedBacklogAdaptiveGroups(limit:10000,filter:{queueId:$queueId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){avg{messages} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/queueMessageOperations.json b/plugins/Cloudflare/v2/dataStreams/queueMessageOperations.json index 1bc1675d..0a075631 100644 --- a/plugins/Cloudflare/v2/dataStreams/queueMessageOperations.json +++ b/plugins/Cloudflare/v2/dataStreams/queueMessageOperations.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$queueId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){queueMessageOperationsAdaptiveGroups(limit:10000,filter:{queueId:$queueId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){count sum{billableOperations bytes}avg{lagTime retryCount}max{messageSize}dimensions{datetimeHour: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} actionType outcome consumerType}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/r2Bandwidth.json b/plugins/Cloudflare/v2/dataStreams/r2Bandwidth.json index 795dd0f4..6d00be10 100644 --- a/plugins/Cloudflare/v2/dataStreams/r2Bandwidth.json +++ b/plugins/Cloudflare/v2/dataStreams/r2Bandwidth.json @@ -10,12 +10,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [ - { - "key": "X-Rate-Limit-Type", - "value": "account-based" - } - ], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!,$bucketName:string!){viewer{accounts(filter:{accountTag:$accountTag}){r2BandwidthUsageAdaptiveGroups(limit:10000,filter:{bucketName:$bucketName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){sum{bytesDownload bytesUpload} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/r2Operations.json b/plugins/Cloudflare/v2/dataStreams/r2Operations.json index 2ceb5da5..9517d061 100644 --- a/plugins/Cloudflare/v2/dataStreams/r2Operations.json +++ b/plugins/Cloudflare/v2/dataStreams/r2Operations.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$bucketName:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){r2OperationsAdaptiveGroups(limit:10000,filter:{bucketName:$bucketName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : 'date' }}_ASC]){sum{requests responseBytes}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : 'date' }} actionType actionStatus}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/r2Storage.json b/plugins/Cloudflare/v2/dataStreams/r2Storage.json index af84de12..865bcf51 100644 --- a/plugins/Cloudflare/v2/dataStreams/r2Storage.json +++ b/plugins/Cloudflare/v2/dataStreams/r2Storage.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$bucketName:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){r2StorageAdaptiveGroups(limit:10000,filter:{bucketName:$bucketName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){max{objectCount payloadSize metadataSize uploadCount}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/realtimeUsage.json b/plugins/Cloudflare/v2/dataStreams/realtimeUsage.json index e63359b2..3035ecad 100644 --- a/plugins/Cloudflare/v2/dataStreams/realtimeUsage.json +++ b/plugins/Cloudflare/v2/dataStreams/realtimeUsage.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$appId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){callsUsageAdaptiveGroups(limit:10000,filter:{appId:$appId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){sum{egressBytes ingressBytes} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} trackType}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/rumPageLoadTiming.json b/plugins/Cloudflare/v2/dataStreams/rumPageLoadTiming.json index 6eea5a64..c3853dfc 100644 --- a/plugins/Cloudflare/v2/dataStreams/rumPageLoadTiming.json +++ b/plugins/Cloudflare/v2/dataStreams/rumPageLoadTiming.json @@ -10,12 +10,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [ - { - "key": "X-Rate-Limit-Type", - "value": "account-based" - } - ], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!,$hostFilter:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumPerformanceEventsAdaptiveGroups(limit:10000,filter:{requestHost_like:$hostFilter,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count sum{visits} quantiles{dnsTimeP75 connectionTimeP75 requestTimeP75 responseTimeP75 firstContentfulPaintP75 pageLoadTimeP75} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json b/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json index 399b3ff1..f57196c9 100644 --- a/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json +++ b/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!,$requestHost:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumPageloadEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end,requestHost_like:$requestHost},orderBy:[count_DESC]){count sum{visits} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json b/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json index 00de4dfc..6cf94e2a 100644 --- a/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json +++ b/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!,$hostFilter:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumWebVitalsEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end,requestHost_like:$hostFilter},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}} quantiles{largestContentfulPaintP75 interactionToNextPaintP75 firstInputDelayP75 cumulativeLayoutShiftP75}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/graphqlQuery.js b/plugins/Cloudflare/v2/dataStreams/scripts/graphqlQuery.js index da1ba865..33240e29 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/graphqlQuery.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/graphqlQuery.js @@ -16,7 +16,16 @@ if (graphqlErrors.length) { const messages = graphqlErrors .map((e) => (e && e.message) || JSON.stringify(e)) .filter(Boolean); - throw new Error('Cloudflare GraphQL error: ' + messages.join(' | ')); + const joined = messages.join(' | '); + // The default query filters on $zoneTag, which is null until a zone is selected. + if (joined.indexOf('empty zone filters') >= 0 || joined.indexOf('empty account filters') >= 0) { + throw new Error( + 'Select a zone or account in "Zone or account", or remove the $zoneTag / $accountTag filter from the query. (' + + joined + + ')' + ); + } + throw new Error('Cloudflare GraphQL error: ' + joined); } // Every array in the response, as a dot path - used to make path errors actionable. @@ -53,16 +62,25 @@ const requestedPath = String( (context && context.config && context.config.pathToData) || '' ).trim(); -if (!requestedPath) { - throw new Error('Set "Path to rows" to the path of the array of rows in the query response.' + candidates()); +// With no path set, use the first array of rows that has no array of rows inside it - +// for a typical query that is data.viewer..0.. A query that +// reads several datasets or several zones needs an explicit path. +const leafArrayPath = () => { + const paths = arrayPaths(body, '', 0, []); + return paths.find((path) => !paths.some((other) => other.indexOf(path + '.') === 0)); +}; +const path = requestedPath || leafArrayPath(); + +if (!path) { + throw new Error('The query returned no array of rows.' + candidates()); } // Tolerate a path written with or without the leading `data.` envelope. -let rows = walk(body, requestedPath); -if (rows === undefined) rows = walk(body.data, requestedPath); +let rows = walk(body, path); +if (rows === undefined) rows = walk(body.data, path); if (rows === undefined || rows === null) { - throw new Error('Nothing found at "' + requestedPath + '".' + candidates()); + throw new Error('Nothing found at "' + path + '".' + candidates()); } if (!Array.isArray(rows)) { rows = [rows]; diff --git a/plugins/Cloudflare/v2/dataStreams/streamCmcd.json b/plugins/Cloudflare/v2/dataStreams/streamCmcd.json index 885c49f0..b2323bf3 100644 --- a/plugins/Cloudflare/v2/dataStreams/streamCmcd.json +++ b/plugins/Cloudflare/v2/dataStreams/streamCmcd.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$videoId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){streamCMCDAdaptiveGroups(limit:10000,filter:{videoId:$videoId,datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count avg{bufferStarvationDuration initialBufferStarvationDuration encodedBitrate} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/streamMinutesViewed.json b/plugins/Cloudflare/v2/dataStreams/streamMinutesViewed.json index 04ce1d80..881de54e 100644 --- a/plugins/Cloudflare/v2/dataStreams/streamMinutesViewed.json +++ b/plugins/Cloudflare/v2/dataStreams/streamMinutesViewed.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$uid:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){streamMinutesViewedAdaptiveGroups(limit:10000,filter:{uid:$uid,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}sum{minutesViewed}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json b/plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json index 271153f6..781458d6 100644 --- a/plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json +++ b/plugins/Cloudflare/v2/dataStreams/turnstileChallenges.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$siteKey:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){turnstileAdaptiveGroups(limit:5000,filter:{siteKey:$siteKey,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/vectorizeQueries.json b/plugins/Cloudflare/v2/dataStreams/vectorizeQueries.json index a0cb1924..ad0320a8 100644 --- a/plugins/Cloudflare/v2/dataStreams/vectorizeQueries.json +++ b/plugins/Cloudflare/v2/dataStreams/vectorizeQueries.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$indexName:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){vectorizeV2QueriesAdaptiveGroups(limit:10000,filter:{indexName:$indexName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count avg{requestDurationMs} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/vectorizeStorage.json b/plugins/Cloudflare/v2/dataStreams/vectorizeStorage.json index 0b7b0454..0f1c85cc 100644 --- a/plugins/Cloudflare/v2/dataStreams/vectorizeStorage.json +++ b/plugins/Cloudflare/v2/dataStreams/vectorizeStorage.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$indexName:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){vectorizeV2StorageAdaptiveGroups(limit:10000,filter:{indexName:$indexName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){max{storedVectorDimensions vectorCount} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/workerBuildMinutes.json b/plugins/Cloudflare/v2/dataStreams/workerBuildMinutes.json index 1e9d08e3..95fa4674 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerBuildMinutes.json +++ b/plugins/Cloudflare/v2/dataStreams/workerBuildMinutes.json @@ -9,12 +9,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [ - { - "key": "X-Rate-Limit-Type", - "value": "account-based" - } - ], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){workersBuildsBuildMinutesAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){sum{buildMinutes} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/workerCacheRequests.json b/plugins/Cloudflare/v2/dataStreams/workerCacheRequests.json index ae7ce029..844cc694 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerCacheRequests.json +++ b/plugins/Cloudflare/v2/dataStreams/workerCacheRequests.json @@ -10,12 +10,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [ - { - "key": "X-Rate-Limit-Type", - "value": "account-based" - } - ], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!,$scriptName:string!){viewer{accounts(filter:{accountTag:$accountTag}){workersCacheRequestsAdaptiveGroups(limit:10000,filter:{scriptName:$scriptName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{requests} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} cacheStatus }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/workerCronRuns.json b/plugins/Cloudflare/v2/dataStreams/workerCronRuns.json index a61d27a9..872228a6 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerCronRuns.json +++ b/plugins/Cloudflare/v2/dataStreams/workerCronRuns.json @@ -9,12 +9,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [ - { - "key": "X-Rate-Limit-Type", - "value": "account-based" - } - ], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!,$scriptName:string!){viewer{accounts(filter:{accountTag:$accountTag}){workersInvocationsScheduled(limit:1000,filter:{scriptName:$scriptName,datetime_geq:$start,datetime_leq:$end},orderBy:[datetime_DESC]){datetime scheduledDatetime cron status cpuTimeUs}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/workerInvocations.json b/plugins/Cloudflare/v2/dataStreams/workerInvocations.json index 3cea310b..3bbe653b 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerInvocations.json +++ b/plugins/Cloudflare/v2/dataStreams/workerInvocations.json @@ -10,7 +10,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$scriptName:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){workersInvocationsAdaptive(limit:10000,filter:{scriptName:$scriptName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{requests errors subrequests}quantiles{cpuTimeP50 cpuTimeP99}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} status scriptName}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/workerSmartPlacement.json b/plugins/Cloudflare/v2/dataStreams/workerSmartPlacement.json index 110118a5..eeb84768 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerSmartPlacement.json +++ b/plugins/Cloudflare/v2/dataStreams/workerSmartPlacement.json @@ -10,12 +10,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [ - { - "key": "X-Rate-Limit-Type", - "value": "account-based" - } - ], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!,$scriptName:string!){viewer{accounts(filter:{accountTag:$accountTag}){workerPlacementAdaptiveGroups(limit:10000,filter:{scriptName:$scriptName,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){sum{requests requestDuration} quantiles{requestDurationP50 requestDurationP99} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} placementUsed }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/workerStaticAssets.json b/plugins/Cloudflare/v2/dataStreams/workerStaticAssets.json index bfb8a1f8..61c9ba98 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerStaticAssets.json +++ b/plugins/Cloudflare/v2/dataStreams/workerStaticAssets.json @@ -10,12 +10,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [ - { - "key": "X-Rate-Limit-Type", - "value": "account-based" - } - ], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!,$scriptName:string!){viewer{accounts(filter:{accountTag:$accountTag}){workersAssetsRequestsAdaptiveGroups(limit:10000,filter:{scriptName:$scriptName,datetime_geq:$start,datetime_leq:$end},orderBy:[sum_requests_DESC]){sum{requests} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown || 'statusCode'}} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/workerSubrequests.json b/plugins/Cloudflare/v2/dataStreams/workerSubrequests.json index ecb6adb6..cc1046ec 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerSubrequests.json +++ b/plugins/Cloudflare/v2/dataStreams/workerSubrequests.json @@ -10,12 +10,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [ - { - "key": "X-Rate-Limit-Type", - "value": "account-based" - } - ], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!,$scriptName:string!){viewer{accounts(filter:{accountTag:$accountTag}){workersSubrequestsAdaptiveGroups(limit:10000,filter:{scriptName:$scriptName,datetime_geq:$start,datetime_leq:$end},orderBy:[sum_subrequests_DESC]){sum{subrequests requestBodySize responseBodySize} quantiles{timeToResponseUsP50 timeToResponseUsP99} dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown || 'hostname'}} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/workersAiInference.json b/plugins/Cloudflare/v2/dataStreams/workersAiInference.json index c40185af..39656770 100644 --- a/plugins/Cloudflare/v2/dataStreams/workersAiInference.json +++ b/plugins/Cloudflare/v2/dataStreams/workersAiInference.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiInferenceAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count sum{totalInputTokens totalOutputTokens totalInferenceTimeMs}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json b/plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json index e9cf4434..f326e606 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){dnsAnalyticsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count avg{processingTimeUs} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventVolume.json b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventVolume.json index f6669b4c..609f7ca5 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventVolume.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventVolume.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$filter:ZoneFirewallEventsAdaptiveByTimeGroupsFilter_InputObject){viewer{zones(filter:{zoneTag:$zoneTag}){firewallEventsAdaptiveByTimeGroups(limit:10000,filter:$filter,orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json index b61d50a1..93c05b0b 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){firewallEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{action {{breakdown}} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/zoneHealthCheckEvents.json b/plugins/Cloudflare/v2/dataStreams/zoneHealthCheckEvents.json index b57b67c8..c4ed925a 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneHealthCheckEvents.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneHealthCheckEvents.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){healthCheckEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count avg{rttMs}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} healthCheckName healthCheckId healthStatus healthChanged failureReason region originIP}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/zoneLoadBalancing.json b/plugins/Cloudflare/v2/dataStreams/zoneLoadBalancing.json index 1cf21eeb..e41ce5b3 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneLoadBalancing.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneLoadBalancing.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){loadBalancingRequestsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{lbName selectedPoolName selectedOriginName coloCode}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/zoneNelReports.json b/plugins/Cloudflare/v2/dataStreams/zoneNelReports.json index 3b57d85c..bcb36438 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneNelReports.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneNelReports.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){nelReportsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/zonePageShield.json b/plugins/Cloudflare/v2/dataStreams/zonePageShield.json index 1767fb6b..8fbf35f4 100644 --- a/plugins/Cloudflare/v2/dataStreams/zonePageShield.json +++ b/plugins/Cloudflare/v2/dataStreams/zonePageShield.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){pageShieldReportsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/zoneTraffic.json b/plugins/Cloudflare/v2/dataStreams/zoneTraffic.json index 66e54a51..df15f906 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneTraffic.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneTraffic.json @@ -10,7 +10,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:{{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'Time!' : 'Date!' }},$end:{{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'Time!' : 'Date!' }}){viewer{zones(filter:{zoneTag:$zoneTag}){rows: {{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'httpRequests1hGroups' : 'httpRequests1dGroups' }}(limit:10000,filter:{ {{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'datetime' : 'date' }}_geq:$start, {{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'datetime' : 'date' }}_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'datetime' : 'date' }}_ASC]){dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 172800 ? 'datetime' : 'date' }}}sum{requests cachedRequests bytes cachedBytes threats pageViews encryptedRequests}uniq{uniques}}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json b/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json index f9f84350..37889c29 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json @@ -7,7 +7,6 @@ "config": { "httpMethod": "post", "endpointPath": "graphql", - "headers": [{ "key": "X-Rate-Limit-Type", "value": "account-based" }], "postBody": { "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){httpRequestsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count sum{edgeResponseBytes visits} dimensions{ {{breakdown}} }}}}}", "variables": { diff --git a/plugins/Cloudflare/v2/docs/README.md b/plugins/Cloudflare/v2/docs/README.md index 4c19eb7a..0162403a 100644 --- a/plugins/Cloudflare/v2/docs/README.md +++ b/plugins/Cloudflare/v2/docs/README.md @@ -144,12 +144,16 @@ Twenty-four further streams back the import and the setup check and are hidden f ### Writing your own GraphQL queries -Cloudflare's GraphQL Analytics API exposes far more datasets than this plugin ships streams for. The **GraphQL Query** stream is an escape hatch: paste a query, tell it where the rows live, and it shapes the result like any other stream. +Cloudflare's GraphQL Analytics API exposes far more datasets than this plugin ships streams for. The **GraphQL Query** stream runs a query you write and shapes the result like any other stream. Its default query shows hourly traffic for the selected zone; edit it from there. -- `start` and `end` (ISO 8601) and `startDate` and `endDate` (`YYYY-MM-DD`) are supplied automatically from the tile's timeframe, so a query can filter with `datetime_geq: $start` or `date_geq: $startDate` without hardcoding dates. -- Anything you put in **Variables** is merged on top, which is how you supply an `accountTag` or `zoneTag` - the plugin config holds neither. -- **Path to data** points at the array of rows, e.g. `data.viewer.zones.0.httpRequests1hGroups`. Get it wrong and the error lists the array paths the response actually contains. -- Choose the **None** timeframe when your query hardcodes its own date filter. +- **Zone or account** fills in the IDs a query needs. Select a zone and the query can use `$zoneTag`, `$zoneTags` (every selected zone, for `zoneTag_in`) and `$accountTag` (the zone's account); select an account and it can use `$accountTag`. On a zone or account perspective, bind the dashboard variable here and one tile works for every zone. +- The timeframe arrives as `$start` and `$end` (`Time!`, ISO 8601) and `$startDate` and `$endDate` (`Date!`, `YYYY-MM-DD`), so a query can filter with `datetime_geq: $start` or `date_geq: $startDate`. Declare only the variables the query uses. +- **Variables** adds your own as a JSON object, and overrides a built-in variable of the same name. +- **Path to rows** can usually stay empty: the stream uses the first array of rows in the response. Set it, for example to `data.viewer.zones.0.httpRequests1hGroups`, when a query reads several datasets or zones. A wrong path is reported with the array paths the response does contain. +- Nested fields become dotted columns, such as `sum.requests` and `dimensions.datetime`. +- Choose the **None** timeframe when the query hard-codes its own dates. + +To find a dataset and its fields, browse Cloudflare's [GraphQL Analytics docs](https://developers.cloudflare.com/analytics/graphql-api/) or its guide to [exploring the schema](https://developers.cloudflare.com/analytics/graphql-api/getting-started/explore-graphql-schema/). The limits query under [Known limitations](#known-limitations) shows how far back and how wide each dataset can go on your plan. ## What gets indexed @@ -255,7 +259,7 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w - **Load balancing analytics is gated per zone**, not per account. Zones without the Load Balancing add-on return an authorization error rather than empty data. - **Pages endpoints cap page size at 10.** Cloudflare rejects any larger `per_page` on the Pages API, so Pages projects and deployments are fetched ten at a time. - **Some resource lists are not paged.** R2 buckets, D1 databases, Queues, load balancer pools, Access applications, Vectorize indexes, Hyperdrive configs, Worker scripts and Worker routes are imported in a single request each. Where Cloudflare's paging behaviour could be proven against real data it is used (zones, accounts, DNS records, Pages projects, KV namespaces, Tunnels and Durable Object namespaces all page); the rest were left unpaged because the endpoint either ignores the paging parameters outright — as `workers/scripts` does — or holds too few records in the tested account to confirm they are honoured. If an account holds more of one of these than Cloudflare returns on a single page, the remainder is not imported. -- **Rate limits.** The REST API allowed 1,200 requests per 300 seconds on the token tested. GraphQL queries are by default limited to 300 per 5 minutes per token, so the analytics streams opt into Cloudflare's [account-based rate limiting](https://developers.cloudflare.com/analytics/graphql-api/account-based-rate-limiting/), which gives each account and each zone its own 300-per-5-minutes budget instead. Every analytics stream issues one request per selected object, so a tile scoped to hundreds of objects can still reach a per-account limit. The **GraphQL Query** stream keeps the per-token limit, because account-based limiting does not support queries that list several zones at the top level. +- **Rate limits.** The REST API allowed 1,200 requests per 300 seconds on the token tested. GraphQL queries are by default limited to 300 per 5 minutes per token, so the plugin opts into Cloudflare's [account-based rate limiting](https://developers.cloudflare.com/analytics/graphql-api/account-based-rate-limiting/), which gives each account and each zone its own 300-per-5-minutes budget instead. Every analytics stream issues one request per selected object, so a tile scoped to hundreds of objects can still reach a per-account limit. Cloudflare documents that account-based limiting does not support a query listing several zones at the top level of `viewer`; such queries worked in testing, but if Cloudflare starts rejecting one in the **GraphQL Query** stream, nest the zones inside `accounts(filter: { accountTag: $accountTag })`. - **A breakdown with very many values is truncated.** Cloudflare caps a GraphQL result at 10,000 rows (5,000 on some streams here). The time buckets above keep time-series streams well inside it, but a breakdown such as DNS Analytics by query name on a busy zone can still exceed it. Those streams order by count, so the rows dropped are the least frequent values rather than the most recent part of the range. - **Hand-written GraphQL queries are unbounded.** The **GraphQL Query** stream runs whatever you give it, so it can hit limits the built-in streams are tuned to avoid: a large `limit` on a multi-dimension dataset can exceed the ~6 MB response cap, and a timeframe wider than that dataset's own cap fails with Cloudflare's error naming the limit. Prefer the pre-aggregated `*Groups` datasets over raw event datasets, and keep `limit` modest. The stream does not page, so your `limit` is the ceiling. diff --git a/plugins/Cloudflare/v2/metadata.json b/plugins/Cloudflare/v2/metadata.json index eb6afe1a..5bfbfd32 100644 --- a/plugins/Cloudflare/v2/metadata.json +++ b/plugins/Cloudflare/v2/metadata.json @@ -91,6 +91,10 @@ { "key": "Authorization", "value": "Bearer {{apiToken}}" + }, + { + "key": "X-Rate-Limit-Type", + "value": "account-based" } ] } From 10e0b8ec62b0393e1fcf725dc546f114d3698b37 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 4 Nov 2026 13:43:33 +0000 Subject: [PATCH 19/27] Replace 19 bespoke GraphQL scripts with a shared graphqlFlatRows.js These scripts each checked for Cloudflare errors, picked the rows, normalised the breakdown value and renamed fields. graphqlFlatRows.js does the first three once, and the renaming moves into the queries as GraphQL aliases (`requests: count`, `sum{ bytes: edgeResponseBytes }`), so every stream keeps its column names and dashboards are unchanged. Values the scripts derived - DNS and DNS Firewall response times in milliseconds, Workers AI average duration and Browser Rendering session duration - are now computed metadata columns over a hidden raw column. Checked by running the new script on each rewritten query's shape and comparing columns with the old scripts' output, comparing live rows before and after on the streams with data, and running every converted stream at every timeframe. Five scripts that do more stay: zoneTraffic (switches datasets), zoneFirewallEvents and turnstileChallenges (plan-limit messages), zoneFirewallEventVolume and accountTraffic (zone details per row). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01FsDuPXY2CFtKbw4Cxn6cRF --- .../Cloudflare/v2/dataStreams/auditLogs.json | 4 +- .../v2/dataStreams/browserRendering.json | 6 +- .../dataStreams/cacheReserveOperations.json | 4 +- .../v2/dataStreams/containerMetrics.json | 4 +- .../v2/dataStreams/dmarcReports.json | 4 +- .../v2/dataStreams/dnsFirewallAnalytics.json | 12 +++- .../v2/dataStreams/emailRouting.json | 4 +- .../v2/dataStreams/gatewayDnsQueries.json | 4 +- .../v2/dataStreams/gatewayHttpRequests.json | 4 +- .../dataStreams/gatewayNetworkSessions.json | 4 +- .../v2/dataStreams/imagesRequests.json | 2 +- .../v2/dataStreams/imagesTransformations.json | 2 +- .../v2/dataStreams/rumPageLoads.json | 4 +- .../v2/dataStreams/scripts/auditLogs.js | 34 ----------- .../dataStreams/scripts/browserRendering.js | 49 ---------------- .../scripts/cacheReserveOperations.js | 34 ----------- .../dataStreams/scripts/containerMetrics.js | 42 -------------- .../v2/dataStreams/scripts/dmarcReports.js | 35 ------------ .../scripts/dnsFirewallAnalytics.js | 41 -------------- .../v2/dataStreams/scripts/emailRouting.js | 34 ----------- .../dataStreams/scripts/gatewayDnsQueries.js | 39 ------------- .../scripts/gatewayHttpRequests.js | 34 ----------- .../scripts/gatewayNetworkSessions.js | 39 ------------- .../v2/dataStreams/scripts/graphqlFlatRows.js | 56 +++++++++++++++++++ .../v2/dataStreams/scripts/imagesRequests.js | 27 --------- .../scripts/imagesTransformations.js | 20 ------- .../v2/dataStreams/scripts/rumPageLoads.js | 35 ------------ .../v2/dataStreams/scripts/streamCmcd.js | 38 ------------- .../dataStreams/scripts/workersAiInference.js | 40 ------------- .../dataStreams/scripts/zoneDnsAnalytics.js | 35 ------------ .../v2/dataStreams/scripts/zoneNelReports.js | 39 ------------- .../v2/dataStreams/scripts/zonePageShield.js | 39 ------------- .../scripts/zoneTrafficBreakdown.js | 35 ------------ .../Cloudflare/v2/dataStreams/streamCmcd.json | 4 +- .../v2/dataStreams/workersAiInference.json | 12 +++- .../v2/dataStreams/zoneDnsAnalytics.json | 12 +++- .../v2/dataStreams/zoneNelReports.json | 4 +- .../v2/dataStreams/zonePageShield.json | 4 +- .../v2/dataStreams/zoneTrafficBreakdown.json | 4 +- 39 files changed, 118 insertions(+), 725 deletions(-) delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/auditLogs.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/browserRendering.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/cacheReserveOperations.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/containerMetrics.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/dmarcReports.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/dnsFirewallAnalytics.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/emailRouting.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/gatewayDnsQueries.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/gatewayHttpRequests.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/gatewayNetworkSessions.js create mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/graphqlFlatRows.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/imagesRequests.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/imagesTransformations.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/rumPageLoads.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/streamCmcd.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/workersAiInference.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/zoneDnsAnalytics.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/zoneNelReports.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/zonePageShield.js delete mode 100644 plugins/Cloudflare/v2/dataStreams/scripts/zoneTrafficBreakdown.js diff --git a/plugins/Cloudflare/v2/dataStreams/auditLogs.json b/plugins/Cloudflare/v2/dataStreams/auditLogs.json index d9d297f5..58e31f6d 100644 --- a/plugins/Cloudflare/v2/dataStreams/auditLogs.json +++ b/plugins/Cloudflare/v2/dataStreams/auditLogs.json @@ -11,14 +11,14 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){auditLogsGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){auditLogsGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){actionCount: count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "accountTag": "{{object.rawId}}", "start": "{{timeframe.start}}", "end": "{{timeframe.end}}" } }, - "postRequestScript": "auditLogs.js", + "postRequestScript": "graphqlFlatRows.js", "errorHandling": { "type": "path", "realm": "payload", diff --git a/plugins/Cloudflare/v2/dataStreams/browserRendering.json b/plugins/Cloudflare/v2/dataStreams/browserRendering.json index 5f27872a..13a0d31e 100644 --- a/plugins/Cloudflare/v2/dataStreams/browserRendering.json +++ b/plugins/Cloudflare/v2/dataStreams/browserRendering.json @@ -8,14 +8,14 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){browserRenderingEventsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count avg{avgConcurrentSessions} min{earliestBrowserStartTime} max{latestBrowserEndTime} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} sessionId {{breakdown}}}}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){browserRenderingEventsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count avg{avgConcurrentSessions} min{startTime: earliestBrowserStartTime} max{endTime: latestBrowserEndTime} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} sessionId {{breakdown}}}}}}}", "variables": { "accountTag": "{{object.rawId}}", "start": "{{timeframe.start}}", "end": "{{timeframe.end}}" } }, - "postRequestScript": "browserRendering.js", + "postRequestScript": "graphqlFlatRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", @@ -68,6 +68,8 @@ { "name": "durationMs", "displayName": "Session Duration", + "computed": true, + "valueExpression": "{{ $['startTime'] && $['endTime'] ? new Date($['endTime']).getTime() - new Date($['startTime']).getTime() : null }}", "shape": "milliseconds", "role": "value" }, diff --git a/plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json b/plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json index f426006f..b5f110d9 100644 --- a/plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json +++ b/plugins/Cloudflare/v2/dataStreams/cacheReserveOperations.json @@ -8,14 +8,14 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){cacheReserveOperationsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){sum{requests}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){cacheReserveOperationsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){sum{operationCount: requests}dimensions{datetime: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "zoneTag": "{{object.rawId}}", "start": "{{timeframe.start}}", "end": "{{timeframe.end}}" } }, - "postRequestScript": "cacheReserveOperations.js", + "postRequestScript": "graphqlFlatRows.js", "errorHandling": { "type": "path", "realm": "payload", diff --git a/plugins/Cloudflare/v2/dataStreams/containerMetrics.json b/plugins/Cloudflare/v2/dataStreams/containerMetrics.json index 1315eb59..5293cc30 100644 --- a/plugins/Cloudflare/v2/dataStreams/containerMetrics.json +++ b/plugins/Cloudflare/v2/dataStreams/containerMetrics.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$applicationId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){containersMetricsAdaptiveGroups(limit:10000,filter:{applicationId:$applicationId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){count avg{cpuUtilization memory containerUptime} sum{rxBytes txBytes} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} {{breakdown}}}}}}}", + "query": "query($accountTag:string!,$applicationId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){containersMetricsAdaptiveGroups(limit:10000,filter:{applicationId:$applicationId,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }}_ASC]){count avg{avgCpuUtilization: cpuUtilization avgMemory: memory avgContainerUptimeMs: containerUptime} sum{sumRxBytes: rxBytes sumTxBytes: txBytes} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 619200 ? 'datetimeHour' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeSixHours' : 'date' }} {{breakdown}}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "applicationId": "{{object.rawId}}", @@ -16,7 +16,7 @@ "end": "{{timeframe.end}}" } }, - "postRequestScript": "containerMetrics.js", + "postRequestScript": "graphqlFlatRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/dmarcReports.json b/plugins/Cloudflare/v2/dataStreams/dmarcReports.json index c108d4be..33717fe3 100644 --- a/plugins/Cloudflare/v2/dataStreams/dmarcReports.json +++ b/plugins/Cloudflare/v2/dataStreams/dmarcReports.json @@ -8,14 +8,14 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){dmarcReportsSourcesAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[sum_totalMatchingMessages_DESC]){sum{totalMatchingMessages dmarc} avg{dmarc} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){dmarcReportsSourcesAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[sum_totalMatchingMessages_DESC]){sum{messageCount: totalMatchingMessages} avg{dmarcPassRate: dmarc} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "zoneTag": "{{object.rawId}}", "start": "{{timeframe.start}}", "end": "{{timeframe.end}}" } }, - "postRequestScript": "dmarcReports.js", + "postRequestScript": "graphqlFlatRows.js", "errorHandling": { "type": "path", "realm": "payload", diff --git a/plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json b/plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json index 9afa20fe..c66b0e9d 100644 --- a/plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json +++ b/plugins/Cloudflare/v2/dataStreams/dnsFirewallAnalytics.json @@ -8,14 +8,14 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){dnsFirewallAnalyticsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count quantiles{processingTimeUsP50} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){dnsFirewallAnalyticsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){queries: count quantiles{processingTimeUsP50} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "accountTag": "{{object.rawId}}", "start": "{{timeframe.start}}", "end": "{{timeframe.end}}" } }, - "postRequestScript": "dnsFirewallAnalytics.js", + "postRequestScript": "graphqlFlatRows.js", "errorHandling": { "type": "path", "realm": "payload", @@ -59,9 +59,17 @@ "shape": "number", "role": "value" }, + { + "name": "processingTimeUsP50", + "displayName": "Median processing time (µs)", + "shape": "number", + "visible": false + }, { "name": "medianProcessingTimeMs", "displayName": "Median Processing Time", + "computed": true, + "valueExpression": "{{ $['processingTimeUsP50'] === undefined || $['processingTimeUsP50'] === null ? null : $['processingTimeUsP50'] / 1000 }}", "shape": "milliseconds" } ], diff --git a/plugins/Cloudflare/v2/dataStreams/emailRouting.json b/plugins/Cloudflare/v2/dataStreams/emailRouting.json index efa3e1c0..8c791dec 100644 --- a/plugins/Cloudflare/v2/dataStreams/emailRouting.json +++ b/plugins/Cloudflare/v2/dataStreams/emailRouting.json @@ -8,14 +8,14 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){emailRoutingAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){emailRoutingAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){messageCount: count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "zoneTag": "{{object.rawId}}", "start": "{{timeframe.start}}", "end": "{{timeframe.end}}" } }, - "postRequestScript": "emailRouting.js", + "postRequestScript": "graphqlFlatRows.js", "errorHandling": { "type": "path", "realm": "payload", diff --git a/plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json b/plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json index 37138fc9..6b387f08 100644 --- a/plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json +++ b/plugins/Cloudflare/v2/dataStreams/gatewayDnsQueries.json @@ -8,14 +8,14 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayResolverQueriesAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayResolverQueriesAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){queryCount: count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", "variables": { "accountTag": "{{object.rawId}}", "start": "{{timeframe.start}}", "end": "{{timeframe.end}}" } }, - "postRequestScript": "gatewayDnsQueries.js", + "postRequestScript": "graphqlFlatRows.js", "errorHandling": { "type": "path", "realm": "payload", diff --git a/plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json b/plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json index d031cb08..08b3a653 100644 --- a/plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json +++ b/plugins/Cloudflare/v2/dataStreams/gatewayHttpRequests.json @@ -8,14 +8,14 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayL7RequestsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayL7RequestsAdaptiveGroups(limit:10000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){requests: count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", "variables": { "accountTag": "{{object.rawId}}", "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", "end": "{{timeframe.end}}" } }, - "postRequestScript": "gatewayHttpRequests.js", + "postRequestScript": "graphqlFlatRows.js", "errorHandling": { "type": "path", "realm": "payload", diff --git a/plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json b/plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json index ac97695d..256dd99c 100644 --- a/plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json +++ b/plugins/Cloudflare/v2/dataStreams/gatewayNetworkSessions.json @@ -8,14 +8,14 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayL4SessionsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){gatewayL4SessionsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){sessionCount: count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", "variables": { "accountTag": "{{object.rawId}}", "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", "end": "{{timeframe.end}}" } }, - "postRequestScript": "gatewayNetworkSessions.js", + "postRequestScript": "graphqlFlatRows.js", "errorHandling": { "type": "path", "realm": "payload", diff --git a/plugins/Cloudflare/v2/dataStreams/imagesRequests.json b/plugins/Cloudflare/v2/dataStreams/imagesRequests.json index 82223801..480a7ade 100644 --- a/plugins/Cloudflare/v2/dataStreams/imagesRequests.json +++ b/plugins/Cloudflare/v2/dataStreams/imagesRequests.json @@ -15,7 +15,7 @@ "end": "{{timeframe.end}}" } }, - "postRequestScript": "imagesRequests.js", + "postRequestScript": "graphqlFlatRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/imagesTransformations.json b/plugins/Cloudflare/v2/dataStreams/imagesTransformations.json index aeee4a94..9e4ea059 100644 --- a/plugins/Cloudflare/v2/dataStreams/imagesTransformations.json +++ b/plugins/Cloudflare/v2/dataStreams/imagesTransformations.json @@ -15,7 +15,7 @@ "end": "{{timeframe.end.split('T')[0]}}" } }, - "postRequestScript": "imagesTransformations.js", + "postRequestScript": "graphqlFlatRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json b/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json index f57196c9..bffb047a 100644 --- a/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json +++ b/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!,$requestHost:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumPageloadEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end,requestHost_like:$requestHost},orderBy:[count_DESC]){count sum{visits} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$requestHost:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumPageloadEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end,requestHost_like:$requestHost},orderBy:[count_DESC]){pageViews: count sum{visits} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", "variables": { "accountTag": "{{object.accountId}}", "start": "{{timeframe.start}}", @@ -16,7 +16,7 @@ "requestHost": "{{'%' + object.name}}" } }, - "postRequestScript": "rumPageLoads.js", + "postRequestScript": "graphqlFlatRows.js", "errorHandling": { "type": "path", "realm": "payload", diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/auditLogs.js b/plugins/Cloudflare/v2/dataStreams/scripts/auditLogs.js deleted file mode 100644 index 641f2945..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/auditLogs.js +++ /dev/null @@ -1,34 +0,0 @@ -// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a -// postRequestScript bypasses the stream's declarative errorHandling entirely, -// so the error is raised here or it would be swallowed into an empty result. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - -// dataStreams/scripts/auditLogs.js -// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the -// key holding the breakdown value inside each row's `dimensions` object varies with the -// user-selected breakdown (dimensions.actionType vs dimensions.actorEmail vs dimensions.resourceType). -// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. - -const dimensionKey = context.config && context.config.breakdown; - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.accounts && - data.data.viewer.accounts[0] && - data.data.viewer.accounts[0].auditLogsGroups) || - []; - -result = groups.map((row) => { - const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; - const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); - - return { - date: row.dimensions && row.dimensions.date, - breakdown: label, - actionCount: Number((row.count !== undefined && row.count !== null ? row.count : 0)) || 0 - }; -}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/browserRendering.js b/plugins/Cloudflare/v2/dataStreams/scripts/browserRendering.js deleted file mode 100644 index 8ac020bb..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/browserRendering.js +++ /dev/null @@ -1,49 +0,0 @@ -// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a -// postRequestScript bypasses the stream's declarative errorHandling entirely, -// so the error is raised here or it would be swallowed into an empty result. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - -// dataStreams/scripts/browserRendering.js -// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the -// key holding the dimension value inside each row's `dimensions` object varies with the -// user-selected breakdown (dimensions.clientLibrary vs dimensions.recordingMode). -// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. -// -// Rows are grouped by date + sessionId (+ the chosen breakdown dimension), so each row's -// min/max aggregates collapse to that one session's actual start/end time - used to derive -// a genuine per-session duration, which the API has no single field for. - -const dimensionKey = context.config && context.config.breakdown; - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.accounts && - data.data.viewer.accounts[0] && - data.data.viewer.accounts[0].browserRenderingEventsAdaptiveGroups) || - []; - -result = groups.map((row) => { - const dims = row.dimensions || {}; - const rawValue = dimensionKey ? dims[dimensionKey] : undefined; - const breakdown = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); - - const startTime = row.min && row.min.earliestBrowserStartTime; - const endTime = row.max && row.max.latestBrowserEndTime; - const durationMs = - startTime && endTime ? new Date(endTime).getTime() - new Date(startTime).getTime() : null; - - return { - date: dims.date, - sessionId: dims.sessionId, - breakdown: breakdown, - count: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0, - durationMs: durationMs, - avgConcurrentSessions: Number((row.avg && row.avg.avgConcurrentSessions) || 0) || 0, - startTime: startTime, - endTime: endTime - }; -}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/cacheReserveOperations.js b/plugins/Cloudflare/v2/dataStreams/scripts/cacheReserveOperations.js deleted file mode 100644 index 9b6b124f..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/cacheReserveOperations.js +++ /dev/null @@ -1,34 +0,0 @@ -// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a -// postRequestScript bypasses the stream's declarative errorHandling entirely, -// so the error is raised here or it would be swallowed into an empty result. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - -// dataStreams/scripts/cacheReserveOperations.js -// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the -// key holding the dimension value inside each row's `dimensions` object varies with the -// user-selected breakdown (dimensions.operationClass vs dimensions.actionStatus). -// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. - -const dimensionKey = context.config && context.config.breakdown; - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.zones && - data.data.viewer.zones[0] && - data.data.viewer.zones[0].cacheReserveOperationsAdaptiveGroups) || - []; - -result = groups.map((row) => { - const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; - const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); - - return { - datetime: row.dimensions && row.dimensions.datetime, - breakdown: label, - operationCount: Number((row.sum && row.sum.requests !== undefined ? row.sum.requests : 0)) || 0 - }; -}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/containerMetrics.js b/plugins/Cloudflare/v2/dataStreams/scripts/containerMetrics.js deleted file mode 100644 index 7beb34ce..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/containerMetrics.js +++ /dev/null @@ -1,42 +0,0 @@ -// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a -// postRequestScript bypasses the stream's declarative errorHandling entirely, -// so the error is raised here or it would be swallowed into an empty result. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - -// dataStreams/scripts/containerMetrics.js -// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the -// key holding the dimension value inside each row's `dimensions` object varies with the -// user-selected breakdown (dimensions.region vs dimensions.location vs dimensions.procType). -// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. - -const dimensionKey = context.config && context.config.breakdown; - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.accounts && - data.data.viewer.accounts[0] && - data.data.viewer.accounts[0].containersMetricsAdaptiveGroups) || - []; - -result = groups.map((row) => { - const dims = row.dimensions || {}; - const rawValue = dimensionKey ? dims[dimensionKey] : undefined; - const breakdown = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); - const avg = row.avg || {}; - const sum = row.sum || {}; - - return { - date: dims.date, - breakdown: breakdown, - count: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0, - avgCpuUtilization: Number(avg.cpuUtilization || 0) || 0, - avgMemory: Number(avg.memory || 0) || 0, - avgContainerUptimeMs: Number(avg.containerUptime || 0) || 0, - sumRxBytes: Number(sum.rxBytes || 0) || 0, - sumTxBytes: Number(sum.txBytes || 0) || 0 - }; -}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/dmarcReports.js b/plugins/Cloudflare/v2/dataStreams/scripts/dmarcReports.js deleted file mode 100644 index b397f0b9..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/dmarcReports.js +++ /dev/null @@ -1,35 +0,0 @@ -// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a -// postRequestScript bypasses the stream's declarative errorHandling entirely, -// so the error is raised here or it would be swallowed into an empty result. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - -// dataStreams/scripts/dmarcReports.js -// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the -// key holding the dimension value inside each row's `dimensions` object varies with the -// user-selected breakdown (dimensions.disposition vs dimensions.domain vs ...). -// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. - -const dimensionKey = context.config && context.config.breakdown; - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.zones && - data.data.viewer.zones[0] && - data.data.viewer.zones[0].dmarcReportsSourcesAdaptiveGroups) || - []; - -result = groups.map((row) => { - const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; - const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); - - return { - date: row.dimensions && row.dimensions.date, - breakdown: label, - messageCount: Number((row.sum && row.sum.totalMatchingMessages) || 0) || 0, - dmarcPassRate: Number((row.avg && row.avg.dmarc) || 0) || 0 - }; -}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/dnsFirewallAnalytics.js b/plugins/Cloudflare/v2/dataStreams/scripts/dnsFirewallAnalytics.js deleted file mode 100644 index cd1ea7e5..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/dnsFirewallAnalytics.js +++ /dev/null @@ -1,41 +0,0 @@ -// dataStreams/scripts/dnsFirewallAnalytics.js -// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the -// key holding the dimension value inside each row's `dimensions` object varies with the -// user-selected breakdown (dimensions.responseCode vs dimensions.queryType vs ...). -// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. -// processingTimeUsP50 is reported by Cloudflare in microseconds; convert to milliseconds. -// -// Cloudflare answers a failed GraphQL query with HTTP 200 and a populated top-level -// `errors` array. A postRequestScript bypasses the stream's declarative `errorHandling`, -// so without this check a genuine failure would silently shape to zero rows instead of -// surfacing as an error. -const graphqlErrors = data && Array.isArray(data.errors) ? data.errors : []; -if (graphqlErrors.length) { - throw new Error( - "Cloudflare GraphQL error: " + - graphqlErrors.map((e) => (e && e.message) || JSON.stringify(e)).join(" | ") - ); -} - -const dimensionKey = context.config && context.config.breakdown; - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.accounts && - data.data.viewer.accounts[0] && - data.data.viewer.accounts[0].dnsFirewallAnalyticsAdaptiveGroups) || - []; - -result = groups.map((row) => { - const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; - const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); - - return { - date: row.dimensions && row.dimensions.date, - breakdown: label, - queries: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0, - medianProcessingTimeMs: Number((row.quantiles && row.quantiles.processingTimeUsP50) || 0) / 1000 - }; -}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/emailRouting.js b/plugins/Cloudflare/v2/dataStreams/scripts/emailRouting.js deleted file mode 100644 index 837d5ff1..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/emailRouting.js +++ /dev/null @@ -1,34 +0,0 @@ -// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a -// postRequestScript bypasses the stream's declarative errorHandling entirely, -// so the error is raised here or it would be swallowed into an empty result. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - -// dataStreams/scripts/emailRouting.js -// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the -// key holding the dimension value inside each row's `dimensions` object varies with the -// user-selected breakdown (dimensions.action vs dimensions.status vs ...). -// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. - -const dimensionKey = context.config && context.config.breakdown; - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.zones && - data.data.viewer.zones[0] && - data.data.viewer.zones[0].emailRoutingAdaptiveGroups) || - []; - -result = groups.map((row) => { - const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; - const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); - - return { - date: row.dimensions && row.dimensions.date, - breakdown: label, - messageCount: Number((row.count !== undefined && row.count !== null ? row.count : 0)) || 0 - }; -}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/gatewayDnsQueries.js b/plugins/Cloudflare/v2/dataStreams/scripts/gatewayDnsQueries.js deleted file mode 100644 index 8b11f27b..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/gatewayDnsQueries.js +++ /dev/null @@ -1,39 +0,0 @@ -// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a -// postRequestScript bypasses the stream's declarative errorHandling entirely, -// so the error is raised here or it would be swallowed into an empty result. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - -// dataStreams/scripts/gatewayDnsQueries.js -// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the -// key holding the dimension value inside each row's `dimensions` object varies with the -// user-selected breakdown (dimensions.resolverDecision vs dimensions.categoryNames vs ...). -// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. - -const dimensionKey = context.config && context.config.breakdown; - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.accounts && - data.data.viewer.accounts[0] && - data.data.viewer.accounts[0].gatewayResolverQueriesAdaptiveGroups) || - []; - -result = groups.map((row) => { - const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; - const label = - rawValue === undefined || rawValue === null || rawValue === "" || (Array.isArray(rawValue) && rawValue.length === 0) - ? "Unknown" - : Array.isArray(rawValue) - ? rawValue.join(", ") - : String(rawValue); - - return { - date: row.dimensions && row.dimensions.date, - breakdown: label, - queryCount: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0 - }; -}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/gatewayHttpRequests.js b/plugins/Cloudflare/v2/dataStreams/scripts/gatewayHttpRequests.js deleted file mode 100644 index 7cebe51e..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/gatewayHttpRequests.js +++ /dev/null @@ -1,34 +0,0 @@ -// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a -// postRequestScript bypasses the stream's declarative errorHandling entirely, -// so the error is raised here or it would be swallowed into an empty result. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - -// dataStreams/scripts/gatewayHttpRequests.js -// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the -// key holding the dimension value inside each row's `dimensions` object varies with the -// user-selected breakdown (dimensions.action vs dimensions.httpHost vs ...). -// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. - -const dimensionKey = context.config && context.config.breakdown; - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.accounts && - data.data.viewer.accounts[0] && - data.data.viewer.accounts[0].gatewayL7RequestsAdaptiveGroups) || - []; - -result = groups.map((row) => { - const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; - const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); - - return { - date: row.dimensions && row.dimensions.date, - breakdown: label, - requests: Number((row.count !== undefined && row.count !== null ? row.count : 0)) || 0 - }; -}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/gatewayNetworkSessions.js b/plugins/Cloudflare/v2/dataStreams/scripts/gatewayNetworkSessions.js deleted file mode 100644 index fcd76918..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/gatewayNetworkSessions.js +++ /dev/null @@ -1,39 +0,0 @@ -// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a -// postRequestScript bypasses the stream's declarative errorHandling entirely, -// so the error is raised here or it would be swallowed into an empty result. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - -// dataStreams/scripts/gatewayNetworkSessions.js -// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the -// key holding the dimension value inside each row's `dimensions` object varies with the -// user-selected breakdown (dimensions.action vs dimensions.destinationIp vs ...). -// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. - -const dimensionKey = context.config && context.config.breakdown; - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.accounts && - data.data.viewer.accounts[0] && - data.data.viewer.accounts[0].gatewayL4SessionsAdaptiveGroups) || - []; - -result = groups.map((row) => { - const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; - const label = - rawValue === undefined || rawValue === null || rawValue === "" || (Array.isArray(rawValue) && rawValue.length === 0) - ? "Unknown" - : Array.isArray(rawValue) - ? rawValue.join(", ") - : String(rawValue); - - return { - date: row.dimensions && row.dimensions.date, - breakdown: label, - sessionCount: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0 - }; -}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/graphqlFlatRows.js b/plugins/Cloudflare/v2/dataStreams/scripts/graphqlFlatRows.js new file mode 100644 index 00000000..73358fd7 --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/scripts/graphqlFlatRows.js @@ -0,0 +1,56 @@ +// dataStreams/scripts/graphqlFlatRows.js +// Shared by the GraphQL analytics streams whose columns use plain names (date, requests, +// avgMemory) rather than the dotted names graphqlRows.js produces (dimensions.date, +// sum.requests). Each query selects a single dataset under one account or one zone, and +// names its fields with GraphQL aliases (`requests: count`, `sum{ bytes: edgeResponseBytes }`). +// This script lifts every field out of the dimensions/sum/avg/min/max/quantiles groups +// under its own (aliased) name, so the alias is the column name. Aliases must therefore +// be unique across the groups of one query. +// +// A script rather than pathToData because Cloudflare answers a failed GraphQL query with +// HTTP 200 and an `errors` array, which the declarative errorHandling never sees. + +const body = data || {}; + +const errors = Array.isArray(body.errors) ? body.errors : []; +if (errors.length) { + api.report.error( + "Cloudflare GraphQL error: " + + errors.map((e) => (e && e.message) || JSON.stringify(e)).join(" | ") + ); +} + +const viewer = (body.data && body.data.viewer) || {}; +const scope = (viewer.accounts || viewer.zones || [])[0] || {}; +const rows = Object.keys(scope) + .map((key) => scope[key]) + .find((value) => Array.isArray(value)) || []; + +// Streams with a `breakdown` parameter interpolate the chosen dimension into the query. +// Its value moves to a stable `breakdown` column (list values joined, empty as "Unknown") +// and the dimension's own column is dropped, since its name changes with the selection. +const breakdownKey = context.config && context.config.breakdown; + +const label = (value) => { + if (Array.isArray(value)) value = value.join(", "); + return value === undefined || value === null || value === "" ? "Unknown" : String(value); +}; + +result = rows.map((row) => { + const out = {}; + Object.keys(row).forEach((key) => { + const value = row[key]; + if (value !== null && typeof value === "object" && !Array.isArray(value)) { + Object.keys(value).forEach((field) => { + out[field] = value[field]; + }); + } else { + out[key] = value; + } + }); + if (breakdownKey) { + out.breakdown = label(row.dimensions && row.dimensions[breakdownKey]); + delete out[breakdownKey]; + } + return out; +}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/imagesRequests.js b/plugins/Cloudflare/v2/dataStreams/scripts/imagesRequests.js deleted file mode 100644 index f1ff0d1d..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/imagesRequests.js +++ /dev/null @@ -1,27 +0,0 @@ -// dataStreams/scripts/imagesRequests.js -// Cloudflare answers a failed GraphQL query with HTTP 200 and a populated `errors` array, -// so the request never looks like a failure and the stream's `errorHandling` does not -// reliably fire on it (confirmed against this endpoint's imagesTransformationsAdaptiveGroups -// node, which returns exactly this shape). Check for it explicitly so a broken/over-wide -// query surfaces as a real error instead of silently shaping to a degenerate row. -const graphqlErrors = (data && data.errors) || []; -if (graphqlErrors.length) { - throw new Error( - "Cloudflare GraphQL error: " + - graphqlErrors.map((e) => (e && e.message) || JSON.stringify(e)).join(" | ") - ); -} - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.accounts && - data.data.viewer.accounts[0] && - data.data.viewer.accounts[0].imagesRequestsAdaptiveGroups) || - []; - -result = groups.map((row) => ({ - date: row.dimensions && row.dimensions.date, - requests: Number((row.sum && row.sum.requests) || 0) || 0 -})); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/imagesTransformations.js b/plugins/Cloudflare/v2/dataStreams/scripts/imagesTransformations.js deleted file mode 100644 index 19ead6ad..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/imagesTransformations.js +++ /dev/null @@ -1,20 +0,0 @@ -// Cloudflare's GraphQL API answers HTTP 200 even when the query failed, and the -// stream-level errorHandling does not reliably fire for that case, so the error -// is raised here explicitly rather than shaping to a misleading empty result. -// -// Note this uses imagesUniqueTransformations, not imagesTransformationsAdaptiveGroups: -// the latter returns INTERNAL_SERVER_ERROR from Cloudflare for every query shape -// and timeframe tested, on every account tested. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - -const accounts = - (data && data.data && data.data.viewer && data.data.viewer.accounts) || []; -const rows = (accounts[0] || {}).imagesUniqueTransformations || []; - -result = rows.map((r) => ({ - date: r.date, - transformations: - typeof r.transformations === "number" ? r.transformations : null, -})); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/rumPageLoads.js b/plugins/Cloudflare/v2/dataStreams/scripts/rumPageLoads.js deleted file mode 100644 index 36a37fbc..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/rumPageLoads.js +++ /dev/null @@ -1,35 +0,0 @@ -// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a -// postRequestScript bypasses the stream's declarative errorHandling entirely, -// so the error is raised here or it would be swallowed into an empty result. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - -// dataStreams/scripts/rumPageLoads.js -// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the -// key holding the dimension value inside each row's `dimensions` object varies with the -// user-selected breakdown (dimensions.countryName vs dimensions.deviceType vs ...). -// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. - -const dimensionKey = context.config && context.config.breakdown; - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.accounts && - data.data.viewer.accounts[0] && - data.data.viewer.accounts[0].rumPageloadEventsAdaptiveGroups) || - []; - -result = groups.map((row) => { - const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; - const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); - - return { - date: row.dimensions && row.dimensions.date, - breakdown: label, - pageViews: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0, - visits: Number((row.sum && row.sum.visits) || 0) || 0 - }; -}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/streamCmcd.js b/plugins/Cloudflare/v2/dataStreams/scripts/streamCmcd.js deleted file mode 100644 index 2d81407f..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/streamCmcd.js +++ /dev/null @@ -1,38 +0,0 @@ -// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a -// postRequestScript bypasses the stream's declarative errorHandling entirely, -// so the error is raised here or it would be swallowed into an empty result. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - -// dataStreams/scripts/streamCmcd.js -// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the -// key holding the dimension value inside each row's `dimensions` object varies with the -// user-selected breakdown (dimensions.country vs dimensions.resolution vs dimensions.streamType). -// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. - -const dimensionKey = context.config && context.config.breakdown; - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.accounts && - data.data.viewer.accounts[0] && - data.data.viewer.accounts[0].streamCMCDAdaptiveGroups) || - []; - -result = groups.map((row) => { - const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; - const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); - const avg = row.avg || {}; - - return { - date: row.dimensions && row.dimensions.date, - breakdown: label, - sampleCount: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0, - avgBufferingDurationMs: Number(avg.bufferStarvationDuration) || 0, - avgStartupBufferingDurationMs: Number(avg.initialBufferStarvationDuration) || 0, - avgEncodedBitrate: Number(avg.encodedBitrate) || 0, - }; -}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/workersAiInference.js b/plugins/Cloudflare/v2/dataStreams/scripts/workersAiInference.js deleted file mode 100644 index 5cf1c49a..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/workersAiInference.js +++ /dev/null @@ -1,40 +0,0 @@ -// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a -// postRequestScript bypasses the stream's declarative errorHandling entirely, -// so the error is raised here or it would be swallowed into an empty result. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - -// dataStreams/scripts/workersAiInference.js -// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the -// key holding the breakdown value inside each row's `dimensions` object varies with the -// user-selected breakdown (dimensions.modelId vs dimensions.requestSource vs dimensions.errorCode). -// Normalise it to a stable `breakdown` column regardless of which dimension was chosen, and -// derive an average inference time per request (the API only returns a per-group total). - -const dimensionKey = context.config && context.config.breakdown; - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.accounts && - data.data.viewer.accounts[0] && - data.data.viewer.accounts[0].aiInferenceAdaptiveGroups) || - []; - -result = groups.map((row) => { - const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; - const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); - const requests = Number((row.count !== undefined && row.count !== null ? row.count : 0)) || 0; - const totalDurationMs = Number((row.sum && row.sum.totalInferenceTimeMs) || 0) || 0; - - return { - date: row.dimensions && row.dimensions.date, - breakdown: label, - requests: requests, - inputTokens: Number((row.sum && row.sum.totalInputTokens) || 0) || 0, - outputTokens: Number((row.sum && row.sum.totalOutputTokens) || 0) || 0, - avgDurationMs: requests > 0 ? Math.round((totalDurationMs / requests) * 100) / 100 : 0 - }; -}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/zoneDnsAnalytics.js b/plugins/Cloudflare/v2/dataStreams/scripts/zoneDnsAnalytics.js deleted file mode 100644 index ec34883f..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/zoneDnsAnalytics.js +++ /dev/null @@ -1,35 +0,0 @@ -// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a -// postRequestScript bypasses the stream's declarative errorHandling entirely, -// so the error is raised here or it would be swallowed into an empty result. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - -// dataStreams/scripts/zoneDnsAnalytics.js -// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the -// key holding the dimension value inside each row's `dimensions` object varies with the -// user-selected breakdown (dimensions.queryName vs dimensions.queryType vs ...). -// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. - -const dimensionKey = context.config && context.config.breakdown; - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.zones && - data.data.viewer.zones[0] && - data.data.viewer.zones[0].dnsAnalyticsAdaptiveGroups) || - []; - -result = groups.map((row) => { - const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; - const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); - - return { - date: row.dimensions && row.dimensions.date, - breakdown: label, - queryCount: Number((row.count !== undefined && row.count !== null ? row.count : 0)) || 0, - avgResponseTimeMs: Number((row.avg && row.avg.processingTimeUs) || 0) / 1000 - }; -}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/zoneNelReports.js b/plugins/Cloudflare/v2/dataStreams/scripts/zoneNelReports.js deleted file mode 100644 index 5a654d74..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/zoneNelReports.js +++ /dev/null @@ -1,39 +0,0 @@ -// dataStreams/scripts/zoneNelReports.js -// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the -// key holding the dimension value inside each row's `dimensions` object varies with the -// user-selected breakdown (dimensions.type vs dimensions.phase vs ...). -// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. -// -// Cloudflare answers a failed GraphQL query (e.g. NEL not entitled on this zone's plan) -// with HTTP 200 and a populated top-level `errors` array. A postRequestScript bypasses -// the stream's declarative `errorHandling`, so without this check a genuine failure -// would silently shape to zero rows instead of surfacing as an error. -const graphqlErrors = data && Array.isArray(data.errors) ? data.errors : []; -if (graphqlErrors.length) { - throw new Error( - "Cloudflare GraphQL error: " + - graphqlErrors.map((e) => (e && e.message) || JSON.stringify(e)).join(" | ") - ); -} - -const dimensionKey = context.config && context.config.breakdown; - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.zones && - data.data.viewer.zones[0] && - data.data.viewer.zones[0].nelReportsAdaptiveGroups) || - []; - -result = groups.map((row) => { - const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; - const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); - - return { - date: row.dimensions && row.dimensions.date, - breakdown: label, - events: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0 - }; -}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/zonePageShield.js b/plugins/Cloudflare/v2/dataStreams/scripts/zonePageShield.js deleted file mode 100644 index ac6a3b4d..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/zonePageShield.js +++ /dev/null @@ -1,39 +0,0 @@ -// dataStreams/scripts/zonePageShield.js -// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the -// key holding the dimension value inside each row's `dimensions` object varies with the -// user-selected breakdown (dimensions.resourceType vs dimensions.urlHost vs ...). -// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. -// -// Cloudflare answers a failed GraphQL query (e.g. Page Shield not entitled on this -// zone's plan) with HTTP 200 and a populated top-level `errors` array. A postRequestScript -// bypasses the stream's declarative `errorHandling`, so without this check a genuine -// failure would silently shape to zero rows instead of surfacing as an error. -const graphqlErrors = data && Array.isArray(data.errors) ? data.errors : []; -if (graphqlErrors.length) { - throw new Error( - "Cloudflare GraphQL error: " + - graphqlErrors.map((e) => (e && e.message) || JSON.stringify(e)).join(" | ") - ); -} - -const dimensionKey = context.config && context.config.breakdown; - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.zones && - data.data.viewer.zones[0] && - data.data.viewer.zones[0].pageShieldReportsAdaptiveGroups) || - []; - -result = groups.map((row) => { - const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; - const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); - - return { - date: row.dimensions && row.dimensions.date, - breakdown: label, - events: Number(row.count !== undefined && row.count !== null ? row.count : 0) || 0 - }; -}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/zoneTrafficBreakdown.js b/plugins/Cloudflare/v2/dataStreams/scripts/zoneTrafficBreakdown.js deleted file mode 100644 index 0873816c..00000000 --- a/plugins/Cloudflare/v2/dataStreams/scripts/zoneTrafficBreakdown.js +++ /dev/null @@ -1,35 +0,0 @@ -// Cloudflare answers HTTP 200 even when the GraphQL query failed, and a -// postRequestScript bypasses the stream's declarative errorHandling entirely, -// so the error is raised here or it would be swallowed into an empty result. -if (data && data.errors && data.errors.length) { - throw new Error("Cloudflare GraphQL error: " + data.errors[0].message); -} - -// dataStreams/scripts/zoneTrafficBreakdown.js -// The GraphQL query interpolates {{breakdown}} into the dimensions selection, so the -// key holding the dimension value inside each row's `dimensions` object varies with the -// user-selected breakdown (dimensions.clientCountryName vs dimensions.cacheStatus vs ...). -// Normalise it to a stable `breakdown` column regardless of which dimension was chosen. - -const dimensionKey = context.config && context.config.breakdown; - -const groups = - (data && - data.data && - data.data.viewer && - data.data.viewer.zones && - data.data.viewer.zones[0] && - data.data.viewer.zones[0].httpRequestsAdaptiveGroups) || - []; - -result = groups.map((row) => { - const rawValue = dimensionKey ? row.dimensions && row.dimensions[dimensionKey] : undefined; - const label = rawValue === undefined || rawValue === null || rawValue === "" ? "Unknown" : String(rawValue); - - return { - breakdown: label, - requests: Number((row.count !== undefined && row.count !== null ? row.count : 0)) || 0, - bytes: Number((row.sum && row.sum.edgeResponseBytes) || 0) || 0, - visits: Number((row.sum && row.sum.visits) || 0) || 0 - }; -}); diff --git a/plugins/Cloudflare/v2/dataStreams/streamCmcd.json b/plugins/Cloudflare/v2/dataStreams/streamCmcd.json index b2323bf3..603c30c5 100644 --- a/plugins/Cloudflare/v2/dataStreams/streamCmcd.json +++ b/plugins/Cloudflare/v2/dataStreams/streamCmcd.json @@ -8,7 +8,7 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$videoId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){streamCMCDAdaptiveGroups(limit:10000,filter:{videoId:$videoId,datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count avg{bufferStarvationDuration initialBufferStarvationDuration encodedBitrate} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", + "query": "query($accountTag:string!,$videoId:string,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){streamCMCDAdaptiveGroups(limit:10000,filter:{videoId:$videoId,datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){sampleCount: count avg{avgBufferingDurationMs: bufferStarvationDuration avgStartupBufferingDurationMs: initialBufferStarvationDuration avgEncodedBitrate: encodedBitrate} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "accountTag": "{{object.accountId}}", "videoId": "{{object.rawId}}", @@ -16,7 +16,7 @@ "end": "{{timeframe.end}}" } }, - "postRequestScript": "streamCmcd.js", + "postRequestScript": "graphqlFlatRows.js", "paging": { "mode": "none" }, "errorHandling": { "type": "path", diff --git a/plugins/Cloudflare/v2/dataStreams/workersAiInference.json b/plugins/Cloudflare/v2/dataStreams/workersAiInference.json index 39656770..ca5632da 100644 --- a/plugins/Cloudflare/v2/dataStreams/workersAiInference.json +++ b/plugins/Cloudflare/v2/dataStreams/workersAiInference.json @@ -8,14 +8,14 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiInferenceAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count sum{totalInputTokens totalOutputTokens totalInferenceTimeMs}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!){viewer{accounts(filter:{accountTag:$accountTag}){aiInferenceAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){requests: count sum{inputTokens: totalInputTokens outputTokens: totalOutputTokens totalInferenceTimeMs}dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "accountTag": "{{object.rawId}}", "start": "{{timeframe.start}}", "end": "{{timeframe.end}}" } }, - "postRequestScript": "workersAiInference.js", + "postRequestScript": "graphqlFlatRows.js", "errorHandling": { "type": "path", "realm": "payload", @@ -68,9 +68,17 @@ "displayName": "Output Tokens", "shape": "number" }, + { + "name": "totalInferenceTimeMs", + "displayName": "Total inference time", + "shape": "milliseconds", + "visible": false + }, { "name": "avgDurationMs", "displayName": "Avg Inference Time", + "computed": true, + "valueExpression": "{{ $['requests'] > 0 ? Math.round(($['totalInferenceTimeMs'] / $['requests']) * 100) / 100 : 0 }}", "shape": ["milliseconds", { "decimalPlaces": 2 }] } ], diff --git a/plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json b/plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json index f326e606..da2ad6fa 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneDnsAnalytics.json @@ -8,14 +8,14 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){dnsAnalyticsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count avg{processingTimeUs} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){dnsAnalyticsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){queryCount: count avg{processingTimeUs} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "zoneTag": "{{object.rawId}}", "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", "end": "{{timeframe.end}}" } }, - "postRequestScript": "zoneDnsAnalytics.js", + "postRequestScript": "graphqlFlatRows.js", "errorHandling": { "type": "path", "realm": "payload", @@ -59,9 +59,17 @@ "shape": "number", "role": "value" }, + { + "name": "processingTimeUs", + "displayName": "Avg response time (µs)", + "shape": "number", + "visible": false + }, { "name": "avgResponseTimeMs", "displayName": "Avg Response Time", + "computed": true, + "valueExpression": "{{ $['processingTimeUs'] === undefined || $['processingTimeUs'] === null ? null : $['processingTimeUs'] / 1000 }}", "shape": "milliseconds" } ], diff --git a/plugins/Cloudflare/v2/dataStreams/zoneNelReports.json b/plugins/Cloudflare/v2/dataStreams/zoneNelReports.json index bcb36438..f868cbe6 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneNelReports.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneNelReports.json @@ -8,14 +8,14 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){nelReportsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){nelReportsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){events: count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "zoneTag": "{{object.rawId}}", "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", "end": "{{timeframe.end}}" } }, - "postRequestScript": "zoneNelReports.js", + "postRequestScript": "graphqlFlatRows.js", "errorHandling": { "type": "path", "realm": "payload", diff --git a/plugins/Cloudflare/v2/dataStreams/zonePageShield.json b/plugins/Cloudflare/v2/dataStreams/zonePageShield.json index 8fbf35f4..8f01634d 100644 --- a/plugins/Cloudflare/v2/dataStreams/zonePageShield.json +++ b/plugins/Cloudflare/v2/dataStreams/zonePageShield.json @@ -8,14 +8,14 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){pageShieldReportsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){pageShieldReportsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){events: count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}}}}}}}", "variables": { "zoneTag": "{{object.rawId}}", "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", "end": "{{timeframe.end}}" } }, - "postRequestScript": "zonePageShield.js", + "postRequestScript": "graphqlFlatRows.js", "errorHandling": { "type": "path", "realm": "payload", diff --git a/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json b/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json index 37889c29..0fe91553 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json @@ -8,14 +8,14 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){httpRequestsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){count sum{edgeResponseBytes visits} dimensions{ {{breakdown}} }}}}}", + "query": "query($zoneTag:string!,$start:Time!,$end:Time!){viewer{zones(filter:{zoneTag:$zoneTag}){httpRequestsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end},orderBy:[count_DESC]){requests: count sum{bytes: edgeResponseBytes visits} dimensions{ {{breakdown}} }}}}}", "variables": { "zoneTag": "{{object.rawId}}", "start": "{{ new Date((timeframe.unixStart + 60) * 1000).toISOString() }}", "end": "{{timeframe.end}}" } }, - "postRequestScript": "zoneTrafficBreakdown.js", + "postRequestScript": "graphqlFlatRows.js", "errorHandling": { "type": "path", "realm": "payload", From c9aeb3d33d7370bb59356a3988e2e672fec9b090 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 4 Nov 2026 14:05:20 +0000 Subject: [PATCH 20/27] Fix RUM host matching and review findings - Web Analytics streams matched any host ending in the zone name (requestHost_like "%example.com" also matches notexample.com). Match the zone's own hostname or its subdomains instead. - Workers AI average duration is no longer rounded in the computed column; the column's decimalPlaces handles display. - GraphQL Query help notes the timeframe variables are not sent with the None timeframe. - README: a stream with many distinct values, such as Browser Rendering's per-session rows, can reach Cloudflare's row cap without a breakdown. - Title Case column names in the new streams, matching the rest of the plugin. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01FsDuPXY2CFtKbw4Cxn6cRF --- .../v2/dataStreams/durableObjectActivity.json | 22 +++++++++---------- .../v2/dataStreams/graphqlQuery.json | 2 +- .../v2/dataStreams/hyperdrivePoolSizes.json | 10 ++++----- .../v2/dataStreams/queueDelayedBacklog.json | 2 +- .../v2/dataStreams/rumPageLoadTiming.json | 11 +++++----- .../v2/dataStreams/rumPageLoads.json | 5 +++-- .../v2/dataStreams/rumWebVitals.json | 5 +++-- .../v2/dataStreams/workerBuildMinutes.json | 2 +- .../v2/dataStreams/workerCacheRequests.json | 2 +- .../v2/dataStreams/workerCronRuns.json | 2 +- .../v2/dataStreams/workerSmartPlacement.json | 4 ++-- .../v2/dataStreams/workerSubrequests.json | 8 +++---- .../v2/dataStreams/workersAiInference.json | 2 +- plugins/Cloudflare/v2/docs/README.md | 4 ++-- 14 files changed, 42 insertions(+), 39 deletions(-) diff --git a/plugins/Cloudflare/v2/dataStreams/durableObjectActivity.json b/plugins/Cloudflare/v2/dataStreams/durableObjectActivity.json index c97a2d04..35402b3c 100644 --- a/plugins/Cloudflare/v2/dataStreams/durableObjectActivity.json +++ b/plugins/Cloudflare/v2/dataStreams/durableObjectActivity.json @@ -49,7 +49,7 @@ }, { "name": "activeTimeMs", - "displayName": "Active time", + "displayName": "Active Time", "computed": true, "valueExpression": "{{ $['sum.activeTime'] === undefined || $['sum.activeTime'] === null ? null : $['sum.activeTime'] / 1000 }}", "shape": "milliseconds" @@ -62,29 +62,29 @@ }, { "name": "cpuTimeMs", - "displayName": "CPU time", + "displayName": "CPU Time", "computed": true, "valueExpression": "{{ $['sum.cpuTime'] === undefined || $['sum.cpuTime'] === null ? null : $['sum.cpuTime'] / 1000 }}", "shape": "milliseconds" }, { "name": "sum.rowsRead", - "displayName": "Rows read", + "displayName": "Rows Read", "shape": "number" }, { "name": "sum.rowsWritten", - "displayName": "Rows written", + "displayName": "Rows Written", "shape": "number" }, { "name": "sum.storageReadUnits", - "displayName": "Storage read units", + "displayName": "Storage Read Units", "shape": "number" }, { "name": "sum.storageWriteUnits", - "displayName": "Storage write units", + "displayName": "Storage Write Units", "shape": "number" }, { @@ -94,27 +94,27 @@ }, { "name": "sum.exceededCpuErrors", - "displayName": "CPU limit errors", + "displayName": "CPU Limit Errors", "shape": "number" }, { "name": "sum.exceededMemoryErrors", - "displayName": "Memory limit errors", + "displayName": "Memory Limit Errors", "shape": "number" }, { "name": "sum.fatalInternalErrors", - "displayName": "Internal errors", + "displayName": "Internal Errors", "shape": "number" }, { "name": "max.activeWebsocketConnections", - "displayName": "Peak WebSocket connections", + "displayName": "Peak WebSocket Connections", "shape": "number" }, { "name": "max.memoryUsageBytes", - "displayName": "Peak memory", + "displayName": "Peak Memory", "shape": "bytes" } ], diff --git a/plugins/Cloudflare/v2/dataStreams/graphqlQuery.json b/plugins/Cloudflare/v2/dataStreams/graphqlQuery.json index a73863a2..5848a737 100644 --- a/plugins/Cloudflare/v2/dataStreams/graphqlQuery.json +++ b/plugins/Cloudflare/v2/dataStreams/graphqlQuery.json @@ -42,7 +42,7 @@ "name": "query", "label": "GraphQL query", "language": "graphql", - "help": "Declare any of these variables to use them: `$start` / `$end` (`Time!`) and `$startDate` / `$endDate` (`Date!`) from the timeframe, and `$zoneTag`, `$zoneTags` (`[string!]`) and `$accountTag` (`string`) from the selected zone or account. Each dataset limits how wide a timeframe it accepts; a wider one fails with the limit named. See the [GraphQL Analytics docs](https://developers.cloudflare.com/analytics/graphql-api/).", + "help": "Declare any of these variables to use them: `$start` / `$end` (`Time!`) and `$startDate` / `$endDate` (`Date!`) from the timeframe (not sent with the **None** timeframe), and `$zoneTag`, `$zoneTags` (`[string!]`) and `$accountTag` (`string`) from the selected zone or account. Each dataset limits how wide a timeframe it accepts; a wider one fails with the limit named. See the [GraphQL Analytics docs](https://developers.cloudflare.com/analytics/graphql-api/).", "defaultValue": "query ($zoneTag: string, $start: Time!, $end: Time!) {\n viewer {\n zones(filter: { zoneTag: $zoneTag }, limit: 1) {\n httpRequests1hGroups(\n limit: 1000\n filter: { datetime_geq: $start, datetime_leq: $end }\n orderBy: [datetime_ASC]\n ) {\n dimensions {\n datetime\n }\n sum {\n requests\n bytes\n cachedRequests\n threats\n }\n uniq {\n uniques\n }\n }\n }\n }\n}", "validation": { "required": true diff --git a/plugins/Cloudflare/v2/dataStreams/hyperdrivePoolSizes.json b/plugins/Cloudflare/v2/dataStreams/hyperdrivePoolSizes.json index 626f57dd..b8e7c17b 100644 --- a/plugins/Cloudflare/v2/dataStreams/hyperdrivePoolSizes.json +++ b/plugins/Cloudflare/v2/dataStreams/hyperdrivePoolSizes.json @@ -43,31 +43,31 @@ }, { "name": "avg.currentPoolSize", - "displayName": "Pool size", + "displayName": "Pool Size", "shape": "number", "role": "value", "decimalPlaces": 1 }, { "name": "avg.availablePoolSlots", - "displayName": "Free slots", + "displayName": "Free Slots", "shape": "number", "decimalPlaces": 1 }, { "name": "avg.waitingClients", - "displayName": "Waiting clients", + "displayName": "Waiting Clients", "shape": "number", "decimalPlaces": 1 }, { "name": "max.waitingClients", - "displayName": "Peak waiting clients", + "displayName": "Peak Waiting Clients", "shape": "number" }, { "name": "max.maxPoolSize", - "displayName": "Pool limit", + "displayName": "Pool Limit", "shape": "number" } ], diff --git a/plugins/Cloudflare/v2/dataStreams/queueDelayedBacklog.json b/plugins/Cloudflare/v2/dataStreams/queueDelayedBacklog.json index 081e2dc7..1355c587 100644 --- a/plugins/Cloudflare/v2/dataStreams/queueDelayedBacklog.json +++ b/plugins/Cloudflare/v2/dataStreams/queueDelayedBacklog.json @@ -43,7 +43,7 @@ }, { "name": "avg.messages", - "displayName": "Delayed messages", + "displayName": "Delayed Messages", "shape": "number", "role": "value", "decimalPlaces": 1 diff --git a/plugins/Cloudflare/v2/dataStreams/rumPageLoadTiming.json b/plugins/Cloudflare/v2/dataStreams/rumPageLoadTiming.json index c3853dfc..9b552fda 100644 --- a/plugins/Cloudflare/v2/dataStreams/rumPageLoadTiming.json +++ b/plugins/Cloudflare/v2/dataStreams/rumPageLoadTiming.json @@ -11,10 +11,11 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!,$hostFilter:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumPerformanceEventsAdaptiveGroups(limit:10000,filter:{requestHost_like:$hostFilter,datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count sum{visits} quantiles{dnsTimeP75 connectionTimeP75 requestTimeP75 responseTimeP75 firstContentfulPaintP75 pageLoadTimeP75} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} }}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$zoneName:string!,$subdomains:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumPerformanceEventsAdaptiveGroups(limit:10000,filter:{OR:[{requestHost:$zoneName},{requestHost_like:$subdomains}],datetime_geq:$start,datetime_leq:$end},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count sum{visits} quantiles{dnsTimeP75 connectionTimeP75 requestTimeP75 responseTimeP75 firstContentfulPaintP75 pageLoadTimeP75} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }} }}}}}", "variables": { "accountTag": "{{object.accountId}}", - "hostFilter": "{{'%' + object.name}}", + "zoneName": "{{object.name}}", + "subdomains": "{{'%.' + object.name}}", "start": "{{timeframe.start}}", "end": "{{timeframe.end}}" } @@ -43,7 +44,7 @@ }, { "name": "count", - "displayName": "Page loads", + "displayName": "Page Loads", "shape": "number", "role": "value" }, @@ -82,14 +83,14 @@ }, { "name": "firstContentfulPaint", - "displayName": "First contentful paint P75", + "displayName": "First Contentful Paint P75", "computed": true, "valueExpression": "{{ $['quantiles.firstContentfulPaintP75'] === undefined || $['quantiles.firstContentfulPaintP75'] === null ? null : $['quantiles.firstContentfulPaintP75'] / 1000 }}", "shape": "milliseconds" }, { "name": "pageLoadTime", - "displayName": "Page load P75", + "displayName": "Page Load P75", "computed": true, "valueExpression": "{{ $['quantiles.pageLoadTimeP75'] === undefined || $['quantiles.pageLoadTimeP75'] === null ? null : $['quantiles.pageLoadTimeP75'] / 1000 }}", "shape": "milliseconds" diff --git a/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json b/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json index bffb047a..934af213 100644 --- a/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json +++ b/plugins/Cloudflare/v2/dataStreams/rumPageLoads.json @@ -8,12 +8,13 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!,$requestHost:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumPageloadEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end,requestHost_like:$requestHost},orderBy:[count_DESC]){pageViews: count sum{visits} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$zoneName:string!,$subdomains:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumPageloadEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end,OR:[{requestHost:$zoneName},{requestHost_like:$subdomains}]},orderBy:[count_DESC]){pageViews: count sum{visits} dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeHour' : 'date' }} {{breakdown}} }}}}}", "variables": { "accountTag": "{{object.accountId}}", "start": "{{timeframe.start}}", "end": "{{timeframe.end}}", - "requestHost": "{{'%' + object.name}}" + "zoneName": "{{object.name}}", + "subdomains": "{{'%.' + object.name}}" } }, "postRequestScript": "graphqlFlatRows.js", diff --git a/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json b/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json index 6cf94e2a..dd865869 100644 --- a/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json +++ b/plugins/Cloudflare/v2/dataStreams/rumWebVitals.json @@ -8,12 +8,13 @@ "httpMethod": "post", "endpointPath": "graphql", "postBody": { - "query": "query($accountTag:string!,$start:Time!,$end:Time!,$hostFilter:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumWebVitalsEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end,requestHost_like:$hostFilter},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}} quantiles{largestContentfulPaintP75 interactionToNextPaintP75 firstInputDelayP75 cumulativeLayoutShiftP75}}}}}", + "query": "query($accountTag:string!,$start:Time!,$end:Time!,$zoneName:string!,$subdomains:string!){viewer{accounts(filter:{accountTag:$accountTag}){rumWebVitalsEventsAdaptiveGroups(limit:5000,filter:{datetime_geq:$start,datetime_leq:$end,OR:[{requestHost:$zoneName},{requestHost_like:$subdomains}]},orderBy:[{{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}_ASC]){count dimensions{date: {{ (timeframe.unixEnd - timeframe.unixStart) <= 5400 ? 'datetimeMinute' : (timeframe.unixEnd - timeframe.unixStart) <= 46800 ? 'datetimeFiveMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 90000 ? 'datetimeFifteenMinutes' : (timeframe.unixEnd - timeframe.unixStart) <= 2764800 ? 'datetimeHour' : 'date' }}} quantiles{largestContentfulPaintP75 interactionToNextPaintP75 firstInputDelayP75 cumulativeLayoutShiftP75}}}}}", "variables": { "accountTag": "{{object.accountId}}", "start": "{{timeframe.start}}", "end": "{{timeframe.end}}", - "hostFilter": "{{'%' + object.name}}" + "zoneName": "{{object.name}}", + "subdomains": "{{'%.' + object.name}}" } }, "postRequestScript": "graphqlRows.js", diff --git a/plugins/Cloudflare/v2/dataStreams/workerBuildMinutes.json b/plugins/Cloudflare/v2/dataStreams/workerBuildMinutes.json index 95fa4674..a129a087 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerBuildMinutes.json +++ b/plugins/Cloudflare/v2/dataStreams/workerBuildMinutes.json @@ -41,7 +41,7 @@ }, { "name": "sum.buildMinutes", - "displayName": "Build minutes", + "displayName": "Build Minutes", "shape": "number", "role": "value" } diff --git a/plugins/Cloudflare/v2/dataStreams/workerCacheRequests.json b/plugins/Cloudflare/v2/dataStreams/workerCacheRequests.json index 844cc694..43d8c2b9 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerCacheRequests.json +++ b/plugins/Cloudflare/v2/dataStreams/workerCacheRequests.json @@ -43,7 +43,7 @@ }, { "name": "dimensions.cacheStatus", - "displayName": "Cache status", + "displayName": "Cache Status", "shape": "string", "role": "label" }, diff --git a/plugins/Cloudflare/v2/dataStreams/workerCronRuns.json b/plugins/Cloudflare/v2/dataStreams/workerCronRuns.json index 872228a6..d55237ad 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerCronRuns.json +++ b/plugins/Cloudflare/v2/dataStreams/workerCronRuns.json @@ -89,7 +89,7 @@ }, { "name": "cpuTime", - "displayName": "CPU time", + "displayName": "CPU Time", "computed": true, "valueExpression": "{{ $['cpuTimeUs'] === undefined || $['cpuTimeUs'] === null ? null : $['cpuTimeUs'] / 1000 }}", "shape": "milliseconds" diff --git a/plugins/Cloudflare/v2/dataStreams/workerSmartPlacement.json b/plugins/Cloudflare/v2/dataStreams/workerSmartPlacement.json index eeb84768..7815243e 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerSmartPlacement.json +++ b/plugins/Cloudflare/v2/dataStreams/workerSmartPlacement.json @@ -43,7 +43,7 @@ }, { "name": "dimensions.placementUsed", - "displayName": "Placement used", + "displayName": "Placement Used", "shape": "string", "role": "label" }, @@ -55,7 +55,7 @@ }, { "name": "sum.requestDuration", - "displayName": "Total duration", + "displayName": "Total Duration", "shape": "milliseconds" }, { diff --git a/plugins/Cloudflare/v2/dataStreams/workerSubrequests.json b/plugins/Cloudflare/v2/dataStreams/workerSubrequests.json index cc1046ec..cdc2f4dd 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerSubrequests.json +++ b/plugins/Cloudflare/v2/dataStreams/workerSubrequests.json @@ -82,12 +82,12 @@ }, { "name": "sum.requestBodySize", - "displayName": "Request bytes", + "displayName": "Request Bytes", "shape": "bytes" }, { "name": "sum.responseBodySize", - "displayName": "Response bytes", + "displayName": "Response Bytes", "shape": "bytes" }, { @@ -104,14 +104,14 @@ }, { "name": "responseTimeP50", - "displayName": "Response time P50", + "displayName": "Response Time P50", "computed": true, "valueExpression": "{{ $['quantiles.timeToResponseUsP50'] === undefined || $['quantiles.timeToResponseUsP50'] === null ? null : $['quantiles.timeToResponseUsP50'] / 1000 }}", "shape": "milliseconds" }, { "name": "responseTimeP99", - "displayName": "Response time P99", + "displayName": "Response Time P99", "computed": true, "valueExpression": "{{ $['quantiles.timeToResponseUsP99'] === undefined || $['quantiles.timeToResponseUsP99'] === null ? null : $['quantiles.timeToResponseUsP99'] / 1000 }}", "shape": "milliseconds" diff --git a/plugins/Cloudflare/v2/dataStreams/workersAiInference.json b/plugins/Cloudflare/v2/dataStreams/workersAiInference.json index ca5632da..f286d542 100644 --- a/plugins/Cloudflare/v2/dataStreams/workersAiInference.json +++ b/plugins/Cloudflare/v2/dataStreams/workersAiInference.json @@ -78,7 +78,7 @@ "name": "avgDurationMs", "displayName": "Avg Inference Time", "computed": true, - "valueExpression": "{{ $['requests'] > 0 ? Math.round(($['totalInferenceTimeMs'] / $['requests']) * 100) / 100 : 0 }}", + "valueExpression": "{{ $['requests'] > 0 ? $['totalInferenceTimeMs'] / $['requests'] : 0 }}", "shape": ["milliseconds", { "decimalPlaces": 2 }] } ], diff --git a/plugins/Cloudflare/v2/docs/README.md b/plugins/Cloudflare/v2/docs/README.md index 0162403a..e8699681 100644 --- a/plugins/Cloudflare/v2/docs/README.md +++ b/plugins/Cloudflare/v2/docs/README.md @@ -253,14 +253,14 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w - **Time buckets follow the timeframe.** Time-series streams return one row per minute for Last hour, per 5 minutes up to 12 hours, per 15 minutes up to a day, hourly up to a week, then six-hourly or hourly up to a month (daily for R2 Operations) and daily beyond. Streams grouped by a dimension you choose, which can have many values, use coarser buckets to stay inside Cloudflare's row cap: 5 minutes for Last hour, 15 minutes up to 12 hours, hourly up to a day and daily beyond. A tile can aggregate these into coarser buckets but never finer ones. - **R2 must be activated before it returns anything.** If R2 has never been enabled in the Cloudflare dashboard, the import step for R2 buckets fails with *"Please enable R2 through the Cloudflare Dashboard"*. The step is optional, so the rest of the import still succeeds - but no R2 objects or metrics appear. - **Zero Trust Access must be enabled** for the Access application import to work; otherwise Cloudflare returns *"Access is not enabled"*. -- **Web Analytics must be enabled per zone.** The RUM datasets are account-scoped and filtered to a zone by hostname, so a zone without the Web Analytics beacon installed returns nothing even though the query succeeds. Traffic from hosts that are not Cloudflare zones is not reachable from a zone-scoped tile. +- **Web Analytics must be enabled per zone.** The RUM datasets are account-scoped and filtered to the zone's own hostname and its subdomains, so a zone without the Web Analytics beacon installed returns nothing even though the query succeeds. Traffic from hosts that are not Cloudflare zones is not reachable from a zone-scoped tile. - **Zero Trust Gateway must be configured** for the Gateway streams to return anything. The datasets are reachable without a Gateway subscription, so an empty result means no proxied traffic rather than a permissions problem. - **Durable Object storage covers SQLite-backed namespaces only.** Cloudflare's account-wide storage dataset cannot be filtered per namespace, so the plugin uses the SQLite storage dataset, which can. Key-value-backed namespaces report no storage. - **Load balancing analytics is gated per zone**, not per account. Zones without the Load Balancing add-on return an authorization error rather than empty data. - **Pages endpoints cap page size at 10.** Cloudflare rejects any larger `per_page` on the Pages API, so Pages projects and deployments are fetched ten at a time. - **Some resource lists are not paged.** R2 buckets, D1 databases, Queues, load balancer pools, Access applications, Vectorize indexes, Hyperdrive configs, Worker scripts and Worker routes are imported in a single request each. Where Cloudflare's paging behaviour could be proven against real data it is used (zones, accounts, DNS records, Pages projects, KV namespaces, Tunnels and Durable Object namespaces all page); the rest were left unpaged because the endpoint either ignores the paging parameters outright — as `workers/scripts` does — or holds too few records in the tested account to confirm they are honoured. If an account holds more of one of these than Cloudflare returns on a single page, the remainder is not imported. - **Rate limits.** The REST API allowed 1,200 requests per 300 seconds on the token tested. GraphQL queries are by default limited to 300 per 5 minutes per token, so the plugin opts into Cloudflare's [account-based rate limiting](https://developers.cloudflare.com/analytics/graphql-api/account-based-rate-limiting/), which gives each account and each zone its own 300-per-5-minutes budget instead. Every analytics stream issues one request per selected object, so a tile scoped to hundreds of objects can still reach a per-account limit. Cloudflare documents that account-based limiting does not support a query listing several zones at the top level of `viewer`; such queries worked in testing, but if Cloudflare starts rejecting one in the **GraphQL Query** stream, nest the zones inside `accounts(filter: { accountTag: $accountTag })`. -- **A breakdown with very many values is truncated.** Cloudflare caps a GraphQL result at 10,000 rows (5,000 on some streams here). The time buckets above keep time-series streams well inside it, but a breakdown such as DNS Analytics by query name on a busy zone can still exceed it. Those streams order by count, so the rows dropped are the least frequent values rather than the most recent part of the range. +- **Results with very many rows are truncated.** Cloudflare caps a GraphQL result at 10,000 rows (5,000 on some streams here). The time buckets above keep most time-series streams well inside it, but a stream with many distinct values can still exceed it: a breakdown such as DNS Analytics by query name on a busy zone, or Browser Rendering, which reports each session separately. Those streams order by count, so the rows dropped are the least frequent values rather than the most recent part of the range. - **Hand-written GraphQL queries are unbounded.** The **GraphQL Query** stream runs whatever you give it, so it can hit limits the built-in streams are tuned to avoid: a large `limit` on a multi-dimension dataset can exceed the ~6 MB response cap, and a timeframe wider than that dataset's own cap fails with Cloudflare's error naming the limit. Prefer the pre-aggregated `*Groups` datasets over raw event datasets, and keep `limit` modest. The stream does not page, so your `limit` is the ceiling. - **Some analytics are only available on paid plans.** Page Shield and Network Error Logs return an authorization error on plans without them; Cache Reserve, Load Balancing and Health Checks are add-ons. A tile for a feature the zone or account is not entitled to shows Cloudflare's authorization error rather than empty data. From 6aecc2d173e1b21826c70bbdd385b6eed1db5547 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 4 Nov 2026 14:07:36 +0000 Subject: [PATCH 21/27] Drop the first-import limitation from the README A data source added on 3 November imported all 64 objects on its first import, so SAAS-9815 no longer reproduces. Remove the limitation until it is confirmed either way. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01FsDuPXY2CFtKbw4Cxn6cRF --- plugins/Cloudflare/v2/docs/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/Cloudflare/v2/docs/README.md b/plugins/Cloudflare/v2/docs/README.md index e8699681..d568a9d4 100644 --- a/plugins/Cloudflare/v2/docs/README.md +++ b/plugins/Cloudflare/v2/docs/README.md @@ -268,6 +268,5 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w - **Tunnel bandwidth is not available.** Cloudflare exposes `cloudflared` traffic metrics from each connector's local metrics endpoint rather than through the API, so Tunnels show connector health only. - **Costs are unitless.** Cloudflare's AI Gateway analytics reports cost without stating a currency, so the plugin shows a plain number rather than assuming one. - **Pages Functions cannot be scoped to a single project.** Cloudflare identifies Pages Functions by an internal script name with no published mapping to the project, so this stream reports all Pages Functions in the account, with the function name as a column. -- **The first import only populates accounts and zones.** Everything below them - Workers, KV namespaces, queues, tunnels, Stream videos, Turnstile widgets and the rest - is imported by steps that run against the accounts and zones the same import has just created, and on a brand new data source those objects are not yet visible when those steps start. They are skipped with a warning, and the **next import picks them all up**. Trigger a re-import from the data source page after adding the plugin rather than waiting for the scheduled one. - **Imports run every 12 hours** by default, so newly created zones and resources are not visible immediately. - **Read-only.** The plugin never creates, modifies or deletes anything in Cloudflare. From a6fdadb5a8d98f911ab5d4f1601561027c43ef2f Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 4 Nov 2026 17:28:09 +0000 Subject: [PATCH 22/27] Update the plugin description and README coverage summary Shorten the metadata description to one sentence that covers the whole plugin, as REVIEW.md asks, and bring "What this plugin monitors" up to date with account-wide traffic, longer zone traffic ranges, 30-day firewall trends, page load timing and the new Worker, Durable Object, Hyperdrive, Queue and R2 metrics. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01FsDuPXY2CFtKbw4Cxn6cRF --- plugins/Cloudflare/v2/docs/README.md | 8 ++++---- plugins/Cloudflare/v2/metadata.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/Cloudflare/v2/docs/README.md b/plugins/Cloudflare/v2/docs/README.md index d568a9d4..fd5e1cc6 100644 --- a/plugins/Cloudflare/v2/docs/README.md +++ b/plugins/Cloudflare/v2/docs/README.md @@ -51,11 +51,11 @@ On save, the plugin verifies the token against Cloudflare's token-verification e ## What this plugin monitors -- **Zone traffic and caching** - requests, bandwidth, cached requests and bytes, page views, unique visitors and cache hit ratio per hour, plus breakdowns by country, status code, cache status, host, device type, HTTP protocol and content type. -- **Security** - firewall and WAF events by rule, service, country, host, user agent or path, with the action Cloudflare took; and SSL certificate inventory with days until expiry. +- **Zone traffic and caching** - requests, bandwidth, cached requests and bytes, page views, unique visitors and cache hit ratio for each zone (hourly for the last two days, daily up to a year) or across every zone in an account, plus breakdowns by country, status code, cache status, host, device type, HTTP protocol and content type. +- **Security** - firewall and WAF events by rule, service, country, host, user agent or path, with the action Cloudflare took, and 30-day event trends on every plan; and SSL certificate inventory with days until expiry. - **DNS and availability** - every DNS record in a zone with its type, content, TTL and proxy status; standalone health checks; and load balancer request distribution and per-origin pool health. -- **Web performance** - Core Web Vitals (Largest Contentful Paint, Interaction to Next Paint, Cumulative Layout Shift) and page-load volume from Cloudflare Web Analytics, per zone. -- **Developer platform** - Worker invocations, errors, subrequests and CPU-time percentiles; R2 bucket operations and stored size; KV operations, latency and stored keys; D1 query counts, rows touched and database size; Queue message operations and backlog; Durable Object invocations and storage; Vectorize and Hyperdrive query volume; Workers AI inference by model; and Pages deployment history with branch and commit. +- **Web performance** - Core Web Vitals (Largest Contentful Paint, Interaction to Next Paint, Cumulative Layout Shift) and page-load volume and timing (DNS, connection, response, first contentful paint, page load) from Cloudflare Web Analytics, per zone. +- **Developer platform** - Worker invocations, errors and CPU-time percentiles, outbound subrequests and response time, cron trigger runs, static asset and Cache API requests, Smart Placement and build minutes; R2 bucket operations, bandwidth and stored size; KV operations, latency and stored keys; D1 query counts, rows touched and database size; Queue message operations and backlog, including delayed messages; Durable Object invocations, active and CPU time, errors, memory and storage; Vectorize query volume; Hyperdrive query volume and connection pool; Workers AI inference by model; and Pages deployment history with branch and commit. - **Dependency mapping** - which Worker binds which KV namespace, R2 bucket, D1 database, queue, Durable Object namespace, Vectorize index or Hyperdrive config, and which zones each Worker serves. - **Zero Trust** - Access application inventory and login attempts, Tunnel connector health, Turnstile challenges, and Gateway DNS, HTTP and network filtering activity. - **Media** - Cloudflare Stream minutes viewed and playback quality, Images request and transformation volume, and Realtime bandwidth. diff --git a/plugins/Cloudflare/v2/metadata.json b/plugins/Cloudflare/v2/metadata.json index 5bfbfd32..0f290df7 100644 --- a/plugins/Cloudflare/v2/metadata.json +++ b/plugins/Cloudflare/v2/metadata.json @@ -6,7 +6,7 @@ "name": "@clarkd", "type": "community" }, - "description": "Monitor your Cloudflare account in SquaredUp - zone traffic, cache performance, firewall and WAF events, DNS records and SSL certificate expiry, plus Workers, R2, KV, D1, Queues, Pages, Tunnels, Load Balancers and Access applications.", + "description": "Monitor traffic, security and DNS across your Cloudflare zones, plus Workers, storage, AI and Zero Trust services and how they depend on each other.", "category": "Cloud Platforms", "type": "hybrid", "schemaVersion": "2.1", From c88c2cd4636fae7548ffe911a34286bc9d94f3bf Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 4 Nov 2026 17:35:30 +0000 Subject: [PATCH 23/27] Add dashboard screenshots Overview, Zone and D1 Database dashboards, listed in metadata.json. The zone name, database name and IDs from the test account are replaced with neutral placeholders. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01FsDuPXY2CFtKbw4Cxn6cRF --- plugins/Cloudflare/v2/metadata.json | 5 +++++ .../Cloudflare/v2/screenshots/d1Database.png | Bin 0 -> 146306 bytes plugins/Cloudflare/v2/screenshots/overview.png | Bin 0 -> 106148 bytes plugins/Cloudflare/v2/screenshots/zone.png | Bin 0 -> 119761 bytes 4 files changed, 5 insertions(+) create mode 100644 plugins/Cloudflare/v2/screenshots/d1Database.png create mode 100644 plugins/Cloudflare/v2/screenshots/overview.png create mode 100644 plugins/Cloudflare/v2/screenshots/zone.png diff --git a/plugins/Cloudflare/v2/metadata.json b/plugins/Cloudflare/v2/metadata.json index 0f290df7..ddb1f689 100644 --- a/plugins/Cloudflare/v2/metadata.json +++ b/plugins/Cloudflare/v2/metadata.json @@ -81,6 +81,11 @@ "label": "Repository" } ], + "screenshots": [ + "https://github.com/squaredup/plugins/blob/main/plugins/Cloudflare/v2/screenshots/overview.png", + "https://github.com/squaredup/plugins/blob/main/plugins/Cloudflare/v2/screenshots/zone.png", + "https://github.com/squaredup/plugins/blob/main/plugins/Cloudflare/v2/screenshots/d1Database.png" + ], "base": { "plugin": "WebAPI", "majorVersion": "1", diff --git a/plugins/Cloudflare/v2/screenshots/d1Database.png b/plugins/Cloudflare/v2/screenshots/d1Database.png new file mode 100644 index 0000000000000000000000000000000000000000..202e69622402c2b43049e7e86b72754616efd53f GIT binary patch literal 146306 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ቁ_N47g@daRjhH)_Jpg$|%weHWwdpD~H4EkY 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

9ma6$BaJmntN+k0iWJZvVT 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 literal 0 HcmV?d00001 diff --git a/plugins/Cloudflare/v2/screenshots/overview.png b/plugins/Cloudflare/v2/screenshots/overview.png new file mode 100644 index 0000000000000000000000000000000000000000..0fdad2fba58df5595d4b230e0cdfa44899c363f4 GIT binary patch literal 106148 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 literal 0 HcmV?d00001 diff --git a/plugins/Cloudflare/v2/screenshots/zone.png b/plugins/Cloudflare/v2/screenshots/zone.png new file mode 100644 index 0000000000000000000000000000000000000000..29aac9d08c4646173f14fddfdf593cbc6daefc36 GIT binary patch literal 119761 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 Date: Wed, 4 Nov 2026 17:37:28 +0000 Subject: [PATCH 24/27] Remove the read-only and coverage callout from the README intro Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01FsDuPXY2CFtKbw4Cxn6cRF --- plugins/Cloudflare/v2/docs/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/Cloudflare/v2/docs/README.md b/plugins/Cloudflare/v2/docs/README.md index fd5e1cc6..ee1f95be 100644 --- a/plugins/Cloudflare/v2/docs/README.md +++ b/plugins/Cloudflare/v2/docs/README.md @@ -1,7 +1,5 @@ Monitor your [Cloudflare](https://www.cloudflare.com) account in SquaredUp - zone traffic and cache performance, firewall and WAF activity, DNS records and SSL certificate expiry, plus the developer platform: Workers, R2, KV, D1, Queues, Pages, Tunnels, Load Balancers and Access applications. Data comes from the [Cloudflare REST API](https://developers.cloudflare.com/api/) and the [GraphQL Analytics API](https://developers.cloudflare.com/analytics/graphql-api/). -> ⚠️ This plugin is **read-only** and never changes anything in your Cloudflare account. It does not cover Logpush, Magic Transit, Magic WAN, Spectrum or Waiting Room. - ## Setup You will need a Cloudflare **API token**. Legacy Global API Keys are not supported. From b4287ea8aa83f7fdbb1b924dd02dcabfe88bbf74 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 4 Nov 2026 17:38:03 +0000 Subject: [PATCH 25/27] Set the plugin author to SquaredUp (first party) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01FsDuPXY2CFtKbw4Cxn6cRF --- plugins/Cloudflare/v2/metadata.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/Cloudflare/v2/metadata.json b/plugins/Cloudflare/v2/metadata.json index ddb1f689..98b1aa29 100644 --- a/plugins/Cloudflare/v2/metadata.json +++ b/plugins/Cloudflare/v2/metadata.json @@ -3,8 +3,8 @@ "displayName": "Cloudflare", "version": "2.0.0", "author": { - "name": "@clarkd", - "type": "community" + "name": "SquaredUp", + "type": "firstParty" }, "description": "Monitor traffic, security and DNS across your Cloudflare zones, plus Workers, storage, AI and Zero Trust services and how they depend on each other.", "category": "Cloud Platforms", From 09a99d0ad5a902a2f71e6e0e22a184dd1c15a65f Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 4 Nov 2026 17:38:37 +0000 Subject: [PATCH 26/27] Name the plugin "Cloudflare" to match v1 Matching the v1 plugin's name makes v2 an upgrade of it rather than a separate plugin. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01FsDuPXY2CFtKbw4Cxn6cRF --- plugins/Cloudflare/v2/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Cloudflare/v2/metadata.json b/plugins/Cloudflare/v2/metadata.json index 98b1aa29..4f2092ba 100644 --- a/plugins/Cloudflare/v2/metadata.json +++ b/plugins/Cloudflare/v2/metadata.json @@ -1,5 +1,5 @@ { - "name": "cloudflare", + "name": "Cloudflare", "displayName": "Cloudflare", "version": "2.0.0", "author": { From f68014e1069961b2e7847c2cf35f077b9d0f5e7f Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 6 Nov 2026 16:06:05 +0000 Subject: [PATCH 27/27] Address Cloudflare v2 review feedback - Add Zone Firewall Event Log (individual events, 30 days on every plan) and Zone Status (zone status as a monitored health state) - Add SSL Protocol and Request Source to Zone Traffic Breakdown - Link Zone, Account and Worker columns to their objects - Title Case option labels; complete the firewall action and service lists and stop accepting typed values - Rename Workers Build Minutes to Worker Build Minutes - Add placeholders to the GraphQL Query object picker - Split the Overview, Account and Zone dashboards into focused dashboards, add an Inventory dashboard, and regroup folders into Account and Zones - README: describe all three config validation checks, fix the Email Routing and Gateway entries, note the missing threat-type breakdown, and use US spelling Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01FsDuPXY2CFtKbw4Cxn6cRF --- .../v2/dataStreams/accountTraffic.json | 16 +- .../v2/dataStreams/graphqlQuery.json | 2 + plugins/Cloudflare/v2/dataStreams/queues.json | 20 +- .../v2/dataStreams/scripts/accountTraffic.js | 1 + .../v2/dataStreams/scripts/queues.js | 69 +- .../v2/dataStreams/scripts/workerRoutes.js | 2 + .../v2/dataStreams/workerBuildMinutes.json | 2 +- .../v2/dataStreams/workerRoutes.json | 50 +- .../v2/dataStreams/workerStaticAssets.json | 4 +- .../v2/dataStreams/workerSubrequests.json | 4 +- .../v2/dataStreams/zoneFirewallEventLog.json | 280 ++ .../dataStreams/zoneFirewallEventVolume.json | 145 +- .../v2/dataStreams/zoneFirewallEvents.json | 4 +- .../Cloudflare/v2/dataStreams/zoneStatus.json | 55 + .../v2/dataStreams/zoneTrafficBreakdown.json | 2 + .../defaultContent/Account/account.dash.json | 766 ++++ .../accountDeveloperPlatform.dash.json | 1063 ++++++ .../Account/accountResources.dash.json | 673 ++++ .../Account/accountZeroTrust.dash.json | 798 ++++ .../v2/defaultContent/Account/manifest.json | 20 + .../v2/defaultContent/Core/account.dash.json | 3249 ----------------- .../v2/defaultContent/Core/manifest.json | 12 - .../v2/defaultContent/Core/zone.dash.json | 3123 ---------------- .../v2/defaultContent/Traffic/manifest.json | 8 - .../Zero Trust/tunnel.dash.json | 6 +- .../loadBalancerPool.dash.json | 2 +- .../v2/defaultContent/Zones/manifest.json | 28 + .../v2/defaultContent/Zones/zone.dash.json | 763 ++++ .../Zones/zoneDnsEmail.dash.json | 693 ++++ .../Zones/zoneSecurity.dash.json | 523 +++ .../Zones/zoneTraffic.dash.json | 756 ++++ .../Zones/zoneWebPerformance.dash.json | 681 ++++ .../v2/defaultContent/inventory.dash.json | 1152 ++++++ .../v2/defaultContent/manifest.json | 14 +- .../v2/defaultContent/overview.dash.json | 1257 +------ plugins/Cloudflare/v2/docs/README.md | 34 +- 36 files changed, 8595 insertions(+), 7682 deletions(-) create mode 100644 plugins/Cloudflare/v2/dataStreams/zoneFirewallEventLog.json create mode 100644 plugins/Cloudflare/v2/dataStreams/zoneStatus.json create mode 100644 plugins/Cloudflare/v2/defaultContent/Account/account.dash.json create mode 100644 plugins/Cloudflare/v2/defaultContent/Account/accountDeveloperPlatform.dash.json create mode 100644 plugins/Cloudflare/v2/defaultContent/Account/accountResources.dash.json create mode 100644 plugins/Cloudflare/v2/defaultContent/Account/accountZeroTrust.dash.json create mode 100644 plugins/Cloudflare/v2/defaultContent/Account/manifest.json delete mode 100644 plugins/Cloudflare/v2/defaultContent/Core/account.dash.json delete mode 100644 plugins/Cloudflare/v2/defaultContent/Core/manifest.json delete mode 100644 plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json delete mode 100644 plugins/Cloudflare/v2/defaultContent/Traffic/manifest.json rename plugins/Cloudflare/v2/defaultContent/{Traffic => Zones}/loadBalancerPool.dash.json (99%) create mode 100644 plugins/Cloudflare/v2/defaultContent/Zones/manifest.json create mode 100644 plugins/Cloudflare/v2/defaultContent/Zones/zone.dash.json create mode 100644 plugins/Cloudflare/v2/defaultContent/Zones/zoneDnsEmail.dash.json create mode 100644 plugins/Cloudflare/v2/defaultContent/Zones/zoneSecurity.dash.json create mode 100644 plugins/Cloudflare/v2/defaultContent/Zones/zoneTraffic.dash.json create mode 100644 plugins/Cloudflare/v2/defaultContent/Zones/zoneWebPerformance.dash.json create mode 100644 plugins/Cloudflare/v2/defaultContent/inventory.dash.json diff --git a/plugins/Cloudflare/v2/dataStreams/accountTraffic.json b/plugins/Cloudflare/v2/dataStreams/accountTraffic.json index b7745127..353e833f 100644 --- a/plugins/Cloudflare/v2/dataStreams/accountTraffic.json +++ b/plugins/Cloudflare/v2/dataStreams/accountTraffic.json @@ -50,11 +50,11 @@ }, { "value": "edgeResponseStatus", - "label": "Status code" + "label": "Status Code" }, { "value": "cacheStatus", - "label": "Cache status" + "label": "Cache Status" }, { "value": "clientRequestHTTPHost", @@ -62,7 +62,7 @@ }, { "value": "clientDeviceType", - "label": "Device type" + "label": "Device Type" } ] } @@ -113,7 +113,15 @@ { "name": "accountName", "displayName": "Account", - "shape": "string" + "shape": "string", + "sourceId": "accountId", + "sourceType": "Cloudflare Account" + }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string", + "visible": false } ], "timeframes": [ diff --git a/plugins/Cloudflare/v2/dataStreams/graphqlQuery.json b/plugins/Cloudflare/v2/dataStreams/graphqlQuery.json index 5848a737..de7cecfe 100644 --- a/plugins/Cloudflare/v2/dataStreams/graphqlQuery.json +++ b/plugins/Cloudflare/v2/dataStreams/graphqlQuery.json @@ -27,6 +27,8 @@ "type": "objects", "name": "target", "label": "Zone or account (optional)", + "placeholder": "Select...", + "searchPlaceholder": "Search...", "matches": { "sourceType": { "type": "oneOf", diff --git a/plugins/Cloudflare/v2/dataStreams/queues.json b/plugins/Cloudflare/v2/dataStreams/queues.json index fd579815..55e32f48 100644 --- a/plugins/Cloudflare/v2/dataStreams/queues.json +++ b/plugins/Cloudflare/v2/dataStreams/queues.json @@ -78,7 +78,15 @@ { "name": "primaryConsumerScript", "displayName": "Primary Consumer", - "shape": "string" + "shape": "string", + "sourceId": "primaryConsumerSourceId", + "sourceType": "Cloudflare Worker" + }, + { + "name": "primaryConsumerSourceId", + "displayName": "Primary Consumer ID", + "shape": "string", + "visible": false }, { "name": "producerScripts", @@ -88,7 +96,15 @@ { "name": "primaryProducerScript", "displayName": "Primary Producer", - "shape": "string" + "shape": "string", + "sourceId": "primaryProducerSourceId", + "sourceType": "Cloudflare Worker" + }, + { + "name": "primaryProducerSourceId", + "displayName": "Primary Producer ID", + "shape": "string", + "visible": false } ], "timeframes": false diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/accountTraffic.js b/plugins/Cloudflare/v2/dataStreams/scripts/accountTraffic.js index 8c30c09e..9f16696a 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/accountTraffic.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/accountTraffic.js @@ -30,5 +30,6 @@ result = groups.map((row) => { bytes: Number(sum.edgeResponseBytes || 0) || 0, visits: Number(sum.visits || 0) || 0, accountName: account.name || account.rawId || "", + accountId: account.rawId || "", }; }); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/queues.js b/plugins/Cloudflare/v2/dataStreams/scripts/queues.js index dc048a08..153a887e 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/queues.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/queues.js @@ -3,39 +3,38 @@ // build their account-scoped GraphQL query. const accountId = (context.objects && context.objects[0] && context.objects[0].rawId) || ""; +// A Worker object's sourceId is ":" (see workerScripts.js), +// so the primary producer and consumer columns can link to their Worker. +const workerSourceId = (script) => (script ? `${accountId}:${script}` : ""); -result = ((data && data.result) || []).map((queue) => ({ - sourceId: queue.queue_id, - queueName: queue.queue_name, - accountId: accountId, - producers: - typeof queue.producers_total_count === "number" - ? queue.producers_total_count - : (queue.producers || []).length, - consumers: - typeof queue.consumers_total_count === "number" - ? queue.consumers_total_count - : (queue.consumers || []).length, - // The consuming Worker script names as a readable list, for display only. - // Array properties are JSON-stringified on import (SAAS-9816), so the - // Queue -> Worker rule correlates on primaryConsumerScript below. - // HTTP-pull consumers have no service name and are filtered out. - consumerScripts: (queue.consumers || []) - .map((c) => c && c.service) - .filter(Boolean) - .join(", "), - primaryConsumerScript: - ((queue.consumers || []).map((c) => c && c.service).filter(Boolean))[0] || - "", - // The producing Worker script names, same display-only reasoning as consumers; - // the producer rule correlates on primaryProducerScript. - producerScripts: (queue.producers || []) - .map((p) => p && p.script) - .filter(Boolean) - .join(", "), - primaryProducerScript: - ((queue.producers || []).map((p) => p && p.script).filter(Boolean))[0] || - "", - createdOn: queue.created_on, - modifiedOn: queue.modified_on, -})); +result = ((data && data.result) || []).map((queue) => { + const consumerScripts = (queue.consumers || []).map((c) => c && c.service).filter(Boolean); + const producerScripts = (queue.producers || []).map((p) => p && p.script).filter(Boolean); + return { + sourceId: queue.queue_id, + queueName: queue.queue_name, + accountId: accountId, + producers: + typeof queue.producers_total_count === "number" + ? queue.producers_total_count + : (queue.producers || []).length, + consumers: + typeof queue.consumers_total_count === "number" + ? queue.consumers_total_count + : (queue.consumers || []).length, + // The consuming Worker script names as a readable list, for display only. + // Array properties are JSON-stringified on import (SAAS-9816), so the + // Queue -> Worker rule correlates on primaryConsumerScript below. + // HTTP-pull consumers have no service name and are filtered out. + consumerScripts: consumerScripts.join(", "), + primaryConsumerScript: consumerScripts[0] || "", + primaryConsumerSourceId: workerSourceId(consumerScripts[0]), + // The producing Worker script names, same display-only reasoning as consumers; + // the producer rule correlates on primaryProducerScript. + producerScripts: producerScripts.join(", "), + primaryProducerScript: producerScripts[0] || "", + primaryProducerSourceId: workerSourceId(producerScripts[0]), + createdOn: queue.created_on, + modifiedOn: queue.modified_on, + }; +}); diff --git a/plugins/Cloudflare/v2/dataStreams/scripts/workerRoutes.js b/plugins/Cloudflare/v2/dataStreams/scripts/workerRoutes.js index adf36671..9f5c45f2 100644 --- a/plugins/Cloudflare/v2/dataStreams/scripts/workerRoutes.js +++ b/plugins/Cloudflare/v2/dataStreams/scripts/workerRoutes.js @@ -20,4 +20,6 @@ result = ((data && data.result) || []) zoneName: zoneName, accountId: accountId, scriptName: route.script, + // A Worker object's sourceId is ":" (see workerScripts.js). + workerSourceId: accountId ? `${accountId}:${route.script}` : "", })); diff --git a/plugins/Cloudflare/v2/dataStreams/workerBuildMinutes.json b/plugins/Cloudflare/v2/dataStreams/workerBuildMinutes.json index a129a087..df9806f1 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerBuildMinutes.json +++ b/plugins/Cloudflare/v2/dataStreams/workerBuildMinutes.json @@ -1,6 +1,6 @@ { "name": "workerBuildMinutes", - "displayName": "Workers Build Minutes", + "displayName": "Worker Build Minutes", "description": "Workers Builds minutes used by an account", "tags": [ "Compute" diff --git a/plugins/Cloudflare/v2/dataStreams/workerRoutes.json b/plugins/Cloudflare/v2/dataStreams/workerRoutes.json index 8902f609..3dcb6f2a 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerRoutes.json +++ b/plugins/Cloudflare/v2/dataStreams/workerRoutes.json @@ -2,13 +2,18 @@ "name": "workerRoutes", "displayName": "Worker Routes", "description": "URL patterns that route requests on a zone to a Worker script", - "tags": ["Workers", "Zone"], + "tags": [ + "Workers", + "Zone" + ], "baseDataSourceName": "httpRequestScopedSingle", "config": { "httpMethod": "get", "endpointPath": "zones/{{object.rawId}}/workers/routes", "postRequestScript": "workerRoutes.js", - "paging": { "mode": "none" }, + "paging": { + "mode": "none" + }, "errorHandling": { "type": "path", "realm": "payload", @@ -16,9 +21,16 @@ } }, "matches": { - "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Zone" + ] + } + }, + "visibility": { + "type": "hidden" }, - "visibility": { "type": "hidden" }, "metadata": [ { "name": "sourceId", @@ -34,13 +46,35 @@ "sourceId": "sourceId", "sourceType": "Cloudflare Worker Route" }, - { "name": "accountId", "displayName": "Account ID", "shape": "string" }, - { "name": "zoneId", "displayName": "Zone ID", "shape": "string" }, - { "name": "zoneName", "displayName": "Zone", "shape": "string" }, + { + "name": "accountId", + "displayName": "Account ID", + "shape": "string" + }, + { + "name": "zoneId", + "displayName": "Zone ID", + "shape": "string" + }, + { + "name": "zoneName", + "displayName": "Zone", + "shape": "string", + "sourceId": "zoneId", + "sourceType": "Cloudflare Zone" + }, { "name": "scriptName", "displayName": "Worker", - "shape": "string" + "shape": "string", + "sourceId": "workerSourceId", + "sourceType": "Cloudflare Worker" + }, + { + "name": "workerSourceId", + "displayName": "Worker ID", + "shape": "string", + "visible": false } ], "timeframes": false diff --git a/plugins/Cloudflare/v2/dataStreams/workerStaticAssets.json b/plugins/Cloudflare/v2/dataStreams/workerStaticAssets.json index 61c9ba98..654f5c33 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerStaticAssets.json +++ b/plugins/Cloudflare/v2/dataStreams/workerStaticAssets.json @@ -44,11 +44,11 @@ "options": [ { "value": "statusCode", - "label": "Status code" + "label": "Status Code" }, { "value": "cacheStatus", - "label": "Cache status" + "label": "Cache Status" }, { "value": "hostname", diff --git a/plugins/Cloudflare/v2/dataStreams/workerSubrequests.json b/plugins/Cloudflare/v2/dataStreams/workerSubrequests.json index cdc2f4dd..4f8d2b16 100644 --- a/plugins/Cloudflare/v2/dataStreams/workerSubrequests.json +++ b/plugins/Cloudflare/v2/dataStreams/workerSubrequests.json @@ -48,11 +48,11 @@ }, { "value": "cacheStatus", - "label": "Cache status" + "label": "Cache Status" }, { "value": "httpResponseStatus", - "label": "Status code" + "label": "Status Code" }, { "value": "requestOutcome", diff --git a/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventLog.json b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventLog.json new file mode 100644 index 00000000..af0c5c96 --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventLog.json @@ -0,0 +1,280 @@ +{ + "name": "zoneFirewallEventLog", + "displayName": "Zone Firewall Event Log", + "description": "Individual firewall events for a zone, newest first, optionally filtered by action and service (latest 1,000 events, up to 30 days on every plan)", + "tags": [ + "Zone", + "Security" + ], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "post", + "endpointPath": "graphql", + "postBody": { + "query": "query($zoneTag:string!,$filter:ZoneFirewallEventsAdaptiveFilter_InputObject){viewer{zones(filter:{zoneTag:$zoneTag}){firewallEventsAdaptive(limit:1000,filter:$filter,orderBy:[datetime_DESC]){datetime action source description ruleId rayName clientIP clientCountryName clientASNDescription clientRequestHTTPHost clientRequestHTTPMethodName clientRequestPath userAgent edgeResponseStatus}}}}", + "variables": { + "zoneTag": "{{object.rawId}}", + "filter": "{{ Object.assign({ datetime_geq: new Date((timeframe.unixStart + 60) * 1000).toISOString(), datetime_leq: timeframe.end }, (typeof actions !== 'undefined' && actions ? [].concat(typeof actions === 'string' && actions.trim().charAt(0) === '[' ? JSON.parse(actions) : actions).map((v) => (v && v.value !== undefined ? v.value : v)).filter((v) => v) : []).length ? { action_in: (typeof actions !== 'undefined' && actions ? [].concat(typeof actions === 'string' && actions.trim().charAt(0) === '[' ? JSON.parse(actions) : actions).map((v) => (v && v.value !== undefined ? v.value : v)).filter((v) => v) : []) } : {}, (typeof sources !== 'undefined' && sources ? [].concat(typeof sources === 'string' && sources.trim().charAt(0) === '[' ? JSON.parse(sources) : sources).map((v) => (v && v.value !== undefined ? v.value : v)).filter((v) => v) : []).length ? { source_in: (typeof sources !== 'undefined' && sources ? [].concat(typeof sources === 'string' && sources.trim().charAt(0) === '[' ? JSON.parse(sources) : sources).map((v) => (v && v.value !== undefined ? v.value : v)).filter((v) => v) : []) } : {}) }}" + } + }, + "postRequestScript": "graphqlFlatRows.js", + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { + "type": "oneOf", + "values": [ + "Cloudflare Zone" + ] + } + }, + "ui": [ + { + "type": "autocomplete", + "name": "actions", + "label": "Action(s)", + "isMulti": true, + "isClearable": true, + "data": { + "source": "fixed", + "values": [ + { + "value": "block", + "label": "Block" + }, + { + "value": "managed_challenge", + "label": "Managed Challenge" + }, + { + "value": "challenge", + "label": "Interactive Challenge" + }, + { + "value": "jschallenge", + "label": "JS Challenge" + }, + { + "value": "connection_close", + "label": "Connection Close" + }, + { + "value": "log", + "label": "Log" + }, + { + "value": "skip", + "label": "Skip" + }, + { + "value": "bypass", + "label": "Bypass" + }, + { + "value": "allow", + "label": "Allow" + } + ] + } + }, + { + "type": "autocomplete", + "name": "sources", + "label": "Service(s)", + "isMulti": true, + "isClearable": true, + "data": { + "source": "fixed", + "values": [ + { + "value": "firewallManaged", + "label": "Managed Rules" + }, + { + "value": "firewallCustom", + "label": "Custom Rules" + }, + { + "value": "rateLimit", + "label": "Rate Limiting Rules" + }, + { + "value": "l7ddos", + "label": "HTTP DDoS Protection" + }, + { + "value": "botFight", + "label": "Bot Fight Mode" + }, + { + "value": "botManagement", + "label": "Bot Management" + }, + { + "value": "bic", + "label": "Browser Integrity Check" + }, + { + "value": "securityLevel", + "label": "Security Level" + }, + { + "value": "ip", + "label": "IP Access Rules" + }, + { + "value": "ipRange", + "label": "IP Range Access Rules" + }, + { + "value": "asn", + "label": "ASN Access Rules" + }, + { + "value": "country", + "label": "Country Access Rules" + }, + { + "value": "uaBlock", + "label": "User Agent Blocking" + }, + { + "value": "zoneLockdown", + "label": "Zone Lockdown" + }, + { + "value": "hot", + "label": "Hotlink Protection" + }, + { + "value": "validation", + "label": "Request Validation" + }, + { + "value": "apiShield", + "label": "API Shield" + }, + { + "value": "dlp", + "label": "Data Loss Prevention" + } + ] + } + } + ], + "metadata": [ + { + "name": "datetime", + "displayName": "Time", + "shape": "date", + "role": "timestamp" + }, + { + "name": "action", + "displayName": "Action", + "shape": "string", + "role": "label" + }, + { + "name": "actionState", + "displayName": "Severity", + "computed": true, + "valueExpression": "{{ $['action'] }}", + "shape": [ + "state", + { + "map": { + "error": [ + "block", + "drop", + "connection_close" + ], + "warning": [ + "challenge", + "managed_challenge", + "jschallenge" + ], + "success": [ + "allow", + "skip", + "log", + "bypass" + ] + } + } + ] + }, + { + "name": "source", + "displayName": "Service", + "shape": "string" + }, + { + "name": "description", + "displayName": "Rule", + "shape": "string" + }, + { + "name": "ruleId", + "displayName": "Rule ID", + "shape": "string", + "visible": false + }, + { + "name": "clientIP", + "displayName": "Client IP", + "shape": "string" + }, + { + "name": "clientCountryName", + "displayName": "Country", + "shape": "string" + }, + { + "name": "clientASNDescription", + "displayName": "ASN", + "shape": "string" + }, + { + "name": "clientRequestHTTPHost", + "displayName": "Host", + "shape": "string" + }, + { + "name": "clientRequestHTTPMethodName", + "displayName": "Method", + "shape": "string" + }, + { + "name": "clientRequestPath", + "displayName": "Path", + "shape": "string" + }, + { + "name": "userAgent", + "displayName": "User Agent", + "shape": "string" + }, + { + "name": "edgeResponseStatus", + "displayName": "Status Code", + "shape": "number" + }, + { + "name": "rayName", + "displayName": "Ray ID", + "shape": "string" + } + ], + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days" + ] +} diff --git a/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventVolume.json b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventVolume.json index 609f7ca5..580724ef 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventVolume.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEventVolume.json @@ -2,7 +2,10 @@ "name": "zoneFirewallEventVolume", "displayName": "Zone Firewall Event Volume", "description": "Firewall event counts over time for a zone, optionally filtered by action and service (up to 30 days on every plan)", - "tags": ["Zone", "Security"], + "tags": [ + "Zone", + "Security" + ], "baseDataSourceName": "httpRequestScopedSingle", "config": { "httpMethod": "post", @@ -24,7 +27,9 @@ "matches": { "sourceType": { "type": "oneOf", - "values": ["Cloudflare Zone"] + "values": [ + "Cloudflare Zone" + ] } }, "ui": [ @@ -34,17 +39,45 @@ "label": "Action(s)", "isMulti": true, "isClearable": true, - "allowCustomValues": true, "data": { "source": "fixed", "values": [ - { "value": "block", "label": "Block" }, - { "value": "managed_challenge", "label": "Managed challenge" }, - { "value": "challenge", "label": "Interactive challenge" }, - { "value": "jschallenge", "label": "JS challenge" }, - { "value": "log", "label": "Log" }, - { "value": "skip", "label": "Skip" }, - { "value": "allow", "label": "Allow" } + { + "value": "block", + "label": "Block" + }, + { + "value": "managed_challenge", + "label": "Managed Challenge" + }, + { + "value": "challenge", + "label": "Interactive Challenge" + }, + { + "value": "jschallenge", + "label": "JS Challenge" + }, + { + "value": "connection_close", + "label": "Connection Close" + }, + { + "value": "log", + "label": "Log" + }, + { + "value": "skip", + "label": "Skip" + }, + { + "value": "bypass", + "label": "Bypass" + }, + { + "value": "allow", + "label": "Allow" + } ] } }, @@ -54,19 +87,81 @@ "label": "Service(s)", "isMulti": true, "isClearable": true, - "allowCustomValues": true, "data": { "source": "fixed", "values": [ - { "value": "firewallManaged", "label": "Managed rules" }, - { "value": "firewallCustom", "label": "Custom rules" }, - { "value": "rateLimit", "label": "Rate limiting rules" }, - { "value": "bic", "label": "Browser Integrity Check" }, - { "value": "securityLevel", "label": "Security level" }, - { "value": "ip", "label": "IP Access rules" }, - { "value": "uaBlock", "label": "User Agent Blocking" }, - { "value": "zoneLockdown", "label": "Zone Lockdown" }, - { "value": "botFight", "label": "Bot Fight Mode" } + { + "value": "firewallManaged", + "label": "Managed Rules" + }, + { + "value": "firewallCustom", + "label": "Custom Rules" + }, + { + "value": "rateLimit", + "label": "Rate Limiting Rules" + }, + { + "value": "l7ddos", + "label": "HTTP DDoS Protection" + }, + { + "value": "botFight", + "label": "Bot Fight Mode" + }, + { + "value": "botManagement", + "label": "Bot Management" + }, + { + "value": "bic", + "label": "Browser Integrity Check" + }, + { + "value": "securityLevel", + "label": "Security Level" + }, + { + "value": "ip", + "label": "IP Access Rules" + }, + { + "value": "ipRange", + "label": "IP Range Access Rules" + }, + { + "value": "asn", + "label": "ASN Access Rules" + }, + { + "value": "country", + "label": "Country Access Rules" + }, + { + "value": "uaBlock", + "label": "User Agent Blocking" + }, + { + "value": "zoneLockdown", + "label": "Zone Lockdown" + }, + { + "value": "hot", + "label": "Hotlink Protection" + }, + { + "value": "validation", + "label": "Request Validation" + }, + { + "value": "apiShield", + "label": "API Shield" + }, + { + "value": "dlp", + "label": "Data Loss Prevention" + } ] } } @@ -88,6 +183,8 @@ "name": "zoneName", "displayName": "Zone", "shape": "string", + "sourceId": "zoneTag", + "sourceType": "Cloudflare Zone", "role": "label" }, { @@ -97,5 +194,11 @@ "visible": false } ], - "timeframes": ["last1hour", "last12hours", "last24hours", "last7days", "last30days"] + "timeframes": [ + "last1hour", + "last12hours", + "last24hours", + "last7days", + "last30days" + ] } diff --git a/plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json index 93c05b0b..fd084dc9 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneFirewallEvents.json @@ -63,9 +63,9 @@ "state", { "map": { - "error": ["block", "drop"], + "error": ["block", "drop", "connection_close"], "warning": ["challenge", "managed_challenge", "jschallenge"], - "success": ["allow", "skip", "log"] + "success": ["allow", "skip", "log", "bypass"] } } ] diff --git a/plugins/Cloudflare/v2/dataStreams/zoneStatus.json b/plugins/Cloudflare/v2/dataStreams/zoneStatus.json new file mode 100644 index 00000000..17e0a2b7 --- /dev/null +++ b/plugins/Cloudflare/v2/dataStreams/zoneStatus.json @@ -0,0 +1,55 @@ +{ + "name": "zoneStatus", + "displayName": "Zone Status", + "description": "Current status of a zone as a health state (paused zones show as warning)", + "tags": ["Zone", "Availability"], + "baseDataSourceName": "httpRequestScopedSingle", + "config": { + "httpMethod": "get", + "endpointPath": "zones/{{object.rawId}}", + "pathToData": "result", + "expandInnerObjects": true, + "paging": { "mode": "none" }, + "errorHandling": { + "type": "path", + "realm": "payload", + "path": "errors.0.message" + } + }, + "matches": { + "sourceType": { "type": "oneOf", "values": ["Cloudflare Zone"] } + }, + "metadata": [ + { "name": "id", "displayName": "Zone ID", "shape": "string", "visible": false }, + { + "name": "name", + "displayName": "Zone", + "shape": "string", + "role": "label", + "sourceId": "id", + "sourceType": "Cloudflare Zone" + }, + { "name": "status", "displayName": "Cloudflare Status", "shape": "string", "visible": false }, + { "name": "paused", "displayName": "Paused", "shape": "boolean" }, + { + "name": "state", + "displayName": "Status", + "computed": true, + "valueExpression": "{{ $['paused'] === true || $['paused'] === 'true' ? 'paused' : $['status'] }}", + "shape": [ + "state", + { + "map": { + "success": ["active"], + "warning": ["pending", "initializing", "read only", "paused"], + "error": ["moved", "deactivated", "deleted"] + } + } + ] + }, + { "name": "plan.name", "displayName": "Plan", "shape": "string" }, + { "name": "type", "displayName": "Zone Type", "shape": "string" }, + { "name": "modified_on", "displayName": "Last Modified", "shape": "date" } + ], + "timeframes": false +} diff --git a/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json b/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json index 0fe91553..ec239ccc 100644 --- a/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json +++ b/plugins/Cloudflare/v2/dataStreams/zoneTrafficBreakdown.json @@ -39,6 +39,8 @@ { "value": "clientRequestHTTPHost", "label": "Host" }, { "value": "clientDeviceType", "label": "Device Type" }, { "value": "clientRequestHTTPProtocol", "label": "HTTP Protocol" }, + { "value": "clientSSLProtocol", "label": "SSL Protocol" }, + { "value": "requestSource", "label": "Request Source" }, { "value": "edgeResponseContentTypeName", "label": "Content Type" } ] } diff --git a/plugins/Cloudflare/v2/defaultContent/Account/account.dash.json b/plugins/Cloudflare/v2/defaultContent/Account/account.dash.json new file mode 100644 index 00000000..a68eb506 --- /dev/null +++ b/plugins/Cloudflare/v2/defaultContent/Account/account.dash.json @@ -0,0 +1,766 @@ +{ + "name": "Account", + "schemaVersion": "1.5", + "timeframe": "none", + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "3bb95490-9698-407a-9dca-511995fe1ebb", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Workers", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerScripts]}}", + "name": "workerScripts", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "count" + } + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count", + "comparisonColumn": "none", + "label": "Workers" + } + } + } + } + }, + { + "i": "eb1d6ac1-f3e8-4935-a262-59e02fac22ad", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Pages Projects", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pagesProjects]}}", + "name": "pagesProjects", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "count" + } + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count", + "comparisonColumn": "none", + "label": "Pages Projects" + } + } + } + } + }, + { + "i": "c206f73b-e9dd-4c97-8de6-153be439f5be", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Tunnels", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[tunnels]}}", + "name": "tunnels", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "count" + } + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count", + "comparisonColumn": "none", + "label": "Tunnels" + } + } + } + } + }, + { + "i": "7f158dbb-3a69-4c68-995e-756e6d6a7d07", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "R2 Buckets", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[r2Buckets]}}", + "name": "r2Buckets", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "count" + } + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count", + "comparisonColumn": "none", + "label": "R2 Buckets" + } + } + } + } + }, + { + "i": "fbb27de7-9d74-4de5-aed2-8b347947c7e5", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Account Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "041c7858-722a-4e36-9e17-fa44ab609ea1", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Tunnels", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[tunnels]}}", + "name": "tunnels", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "tunnelName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "tunnelName", + "stateColumn": "status", + "sublabel": "tunnelType", + "linkColumn": "tunnelName", + "columns": 2 + } + } + } + } + }, + { + "i": "36f99add-606b-4848-8e56-7dfdf94c824b", + "x": 0, + "y": 5, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Requests by Zone", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accountTraffic]}}", + "name": "accountTraffic", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "zoneTag" + }, + "sort": { + "by": [ + [ + "datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "datetime", + "yAxisColumn": [ + "requests" + ], + "seriesColumn": "zoneName", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + }, + "timeframe": "last24hours" + } + }, + { + "i": "2789dab8-bd9d-4cf9-b5d4-9e1ed480084f", + "x": 0, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Traffic by Country", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accountTraffic]}}", + "name": "accountTraffic", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "clientCountryName" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "requests_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "requests_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "horizontal", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + }, + "timeframe": "last24hours" + } + }, + { + "i": "8eb403cb-7ab9-46b2-84df-2aa0ed1c22ca", + "x": 2, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Traffic by Status Code", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accountTraffic]}}", + "name": "accountTraffic", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "edgeResponseStatus" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "requests_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "requests_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "horizontal", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + }, + "timeframe": "last24hours" + } + }, + { + "i": "a38a89d8-b533-4bef-bbbb-3bfefb3f44ba", + "x": 0, + "y": 11, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Audit Log Actions", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[auditLogs]}}", + "name": "auditLogs", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "actionType" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "actionCount" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "actionCount_sum", + "comparisonColumn": "none", + "label": "Audit Log Actions" + } + } + } + } + }, + { + "i": "463aafc7-e7fe-483a-9415-135d591794ab", + "x": 1, + "y": 11, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Audit Log Actions Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[auditLogs]}}", + "name": "auditLogs", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "actionType" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "actionCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "actionCount_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "b674edbe-1b30-41b5-a4fa-08bf7ad4ffb5", + "x": 0, + "y": 14, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Top Audit Log Actions", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[auditLogs]}}", + "name": "auditLogs", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "actionType" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "actionCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "actionCount_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "actionCount_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v2/defaultContent/Account/accountDeveloperPlatform.dash.json b/plugins/Cloudflare/v2/defaultContent/Account/accountDeveloperPlatform.dash.json new file mode 100644 index 00000000..b6ab010c --- /dev/null +++ b/plugins/Cloudflare/v2/defaultContent/Account/accountDeveloperPlatform.dash.json @@ -0,0 +1,1063 @@ +{ + "name": "Account Developer Platform", + "schemaVersion": "1.5", + "timeframe": "none", + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "0e7ae631-b894-4f67-a73a-b9e61ce540f9", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "AI Inference Requests", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workersAiInference]}}", + "name": "workersAiInference", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "modelId" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "requests_sum", + "comparisonColumn": "none", + "label": "AI Inference Requests" + } + } + } + } + }, + { + "i": "685debee-fe22-4057-be74-f16010314596", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "AI Output Tokens", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workersAiInference]}}", + "name": "workersAiInference", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "modelId" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "outputTokens" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "outputTokens_sum", + "comparisonColumn": "none", + "label": "AI Output Tokens" + } + } + } + } + }, + { + "i": "b6731e3d-91a3-4ead-9685-7df79e235ce0", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Pages Function Requests", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pagesFunctionsInvocations]}}", + "name": "pagesFunctionsInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.requests_sum", + "comparisonColumn": "none", + "label": "Pages Function Requests" + } + } + } + } + }, + { + "i": "885088db-eba0-4a67-a170-c12c84b61c3c", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Image Requests", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[imagesRequests]}}", + "name": "imagesRequests", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "requests_sum", + "comparisonColumn": "none", + "label": "Image Requests" + } + } + } + } + }, + { + "i": "33b7c30d-8dea-42a1-96d8-a885c9119f0a", + "x": 0, + "y": 2, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Image Transformations", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[imagesTransformations]}}", + "name": "imagesTransformations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "transformations" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "transformations_sum", + "comparisonColumn": "none", + "label": "Image Transformations" + } + } + } + } + }, + { + "i": "6ebe2742-9444-4be7-9edc-1c5b1e113633", + "x": 1, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Workers AI Requests by Model", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workersAiInference]}}", + "name": "workersAiInference", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "modelId" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "requests_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "requests_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "e3b25cc5-489a-4604-96ce-d49e3ee5b6e6", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Workers AI Token Usage", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workersAiInference]}}", + "name": "workersAiInference", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "modelId" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "inputTokens" + ] + }, + { + "type": "sum", + "names": [ + "outputTokens" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "inputTokens_sum", + "outputTokens_sum" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "2d7e5b1b-394e-4111-91de-2aa319f7fea8", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Workers AI Inference Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workersAiInference]}}", + "name": "workersAiInference", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "modelId" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "avgDurationMs" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "avgDurationMs_mean" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "a43ecf79-6372-4f65-bec5-d9e8c925d643", + "x": 0, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Pages Functions Requests and Errors", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pagesFunctionsInvocations]}}", + "name": "pagesFunctionsInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetime", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + }, + { + "type": "sum", + "names": [ + "sum.errors" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.datetime_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byDay", + "yAxisColumn": [ + "sum.requests_sum", + "sum.errors_sum" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "76b7293c-87ef-41eb-97c3-3633f59732de", + "x": 2, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Top Pages Functions by Requests", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pagesFunctionsInvocations]}}", + "name": "pagesFunctionsInvocations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.scriptName", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "sum.requests_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "dimensions.scriptName_uniqueValues", + "yAxisData": [ + "sum.requests_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "ed67a1f0-321c-48e0-98da-937932cbe709", + "x": 0, + "y": 11, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Image Requests Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[imagesRequests]}}", + "name": "imagesRequests", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "requests_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "f1b12eaa-907d-4268-8481-fad2f24f707a", + "x": 2, + "y": 11, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Image Transformations Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[imagesTransformations]}}", + "name": "imagesTransformations", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "transformations" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "transformations_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "18fdde70-9cd8-4d1b-8b5c-0b06ccd397cd", + "x": 0, + "y": 14, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Browser Rendering Session Duration", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[browserRendering]}}", + "name": "browserRendering", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "clientLibrary" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "durationMs" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "durationMs_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "b7a3742d-41bb-42f0-8588-22ae18ba6cc3", + "x": 2, + "y": 14, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Browser Rendering Sessions by Client Library", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[browserRendering]}}", + "name": "browserRendering", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "clientLibrary" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "distinctCount", + "names": [ + "sessionId" + ] + } + ] + }, + "sort": { + "by": [ + [ + "sessionId_distinctCount", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "sessionId_distinctCount" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "a92b1e43-9903-4d5d-9941-6dd4c1e7f726", + "x": 0, + "y": 17, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Worker Build Minutes", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerBuildMinutes]}}", + "name": "workerBuildMinutes", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetime", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.buildMinutes" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byDay", + "yAxisColumn": [ + "sum.buildMinutes_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + }, + "timeframe": "last30days" + } + } + ] + } +} diff --git a/plugins/Cloudflare/v2/defaultContent/Account/accountResources.dash.json b/plugins/Cloudflare/v2/defaultContent/Account/accountResources.dash.json new file mode 100644 index 00000000..79a39495 --- /dev/null +++ b/plugins/Cloudflare/v2/defaultContent/Account/accountResources.dash.json @@ -0,0 +1,673 @@ +{ + "name": "Account Resources", + "schemaVersion": "1.5", + "timeframe": "none", + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "5c67e20d-99f0-4dab-b8c6-13a5f0fdf92b", + "x": 0, + "y": 0, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Workers", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerScripts]}}", + "name": "workerScripts", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "scriptName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "scriptName", + "usageModel", + "handlers", + "placementMode", + "modifiedOn" + ], + "hiddenColumns": [ + "sourceId", + "accountId", + "logpush", + "createdOn" + ] + } + } + } + } + }, + { + "i": "075c1543-3d1f-4d74-a658-dc6e19575764", + "x": 2, + "y": 0, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Pages Projects", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[pagesProjects]}}", + "name": "pagesProjects", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "projectName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "projectName", + "latestDeploymentStatus", + "productionBranch", + "domains", + "latestDeploymentOn" + ], + "hiddenColumns": [ + "sourceId", + "accountId", + "subdomain", + "createdOn" + ] + } + } + } + } + }, + { + "i": "7b5a1c5b-ad5d-4cee-b6fa-4210171976e8", + "x": 0, + "y": 4, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "R2 Buckets", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[r2Buckets]}}", + "name": "r2Buckets", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "bucketName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "bucketName", + "location", + "storageClass", + "createdOn" + ], + "hiddenColumns": [ + "sourceId", + "accountId" + ] + } + } + } + } + }, + { + "i": "65d57e58-56be-42b5-86cc-735ef92fa7d8", + "x": 2, + "y": 4, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "KV Namespaces", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[kvNamespaces]}}", + "name": "kvNamespaces", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "namespaceTitle", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "namespaceTitle", + "supportsUrlEncoding" + ], + "hiddenColumns": [ + "sourceId", + "accountId" + ] + } + } + } + } + }, + { + "i": "70461624-c21e-4501-9244-23a15edd4add", + "x": 0, + "y": 8, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "D1 Databases", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[d1Databases]}}", + "name": "d1Databases", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "databaseName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "databaseName", + "numTables", + "fileSize", + "version", + "createdOn" + ], + "hiddenColumns": [ + "sourceId", + "accountId" + ] + } + } + } + } + }, + { + "i": "c25cb5ba-cd50-4a90-8871-b99f8c57bcf7", + "x": 2, + "y": 8, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Queues", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[queues]}}", + "name": "queues", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "queueName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "queueName", + "primaryProducerScript", + "primaryConsumerScript", + "producers", + "consumers", + "modifiedOn" + ], + "hiddenColumns": [ + "sourceId", + "accountId", + "createdOn", + "producerScripts", + "consumerScripts", + "primaryProducerSourceId", + "primaryConsumerSourceId" + ] + } + } + } + } + }, + { + "i": "83f57d60-3e02-40dd-8ab5-9ca6bed4fea9", + "x": 0, + "y": 12, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Durable Object Namespaces", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[durableObjectNamespaces]}}", + "name": "durableObjectNamespaces", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "namespaceName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "namespaceName", + "scriptName", + "className", + "usesSqlite" + ], + "hiddenColumns": [ + "sourceId", + "accountId" + ] + } + } + } + } + }, + { + "i": "2336e698-182b-4dc7-83bf-5d104c88eead", + "x": 2, + "y": 12, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Vectorize Indexes", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[vectorizeIndexes]}}", + "name": "vectorizeIndexes", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "indexName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "indexName", + "dimensions", + "metric", + "createdOn" + ], + "hiddenColumns": [ + "sourceId", + "accountId", + "modifiedOn" + ] + } + } + } + } + }, + { + "i": "7c8fd8d9-542a-4665-9621-e7ed1b8583b7", + "x": 0, + "y": 16, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Hyperdrive Configs", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[hyperdriveConfigs]}}", + "name": "hyperdriveConfigs", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "configName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "configName", + "database", + "host", + "scheme" + ], + "hiddenColumns": [ + "sourceId", + "accountId", + "cachingDisabled" + ] + } + } + } + } + }, + { + "i": "cd0f4644-c131-45c5-aef2-0ec8d91ca62e", + "x": 2, + "y": 16, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Load Balancer Pools", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[loadBalancerPools]}}", + "name": "loadBalancerPools", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "poolName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "poolName", + "enabled", + "originCount", + "minimumOrigins", + "modifiedOn" + ], + "hiddenColumns": [ + "sourceId", + "accountId", + "monitorId", + "createdOn" + ] + } + } + } + } + }, + { + "i": "f342d86a-84d2-4dec-999c-ef0c39f94870", + "x": 0, + "y": 20, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Access Applications", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[accessApps]}}", + "name": "accessApps", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "appName", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "appName", + "appType", + "domain", + "sessionDuration", + "appLauncherVisible" + ], + "hiddenColumns": [ + "sourceId", + "accountId", + "createdOn", + "modifiedOn" + ] + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v2/defaultContent/Account/accountZeroTrust.dash.json b/plugins/Cloudflare/v2/defaultContent/Account/accountZeroTrust.dash.json new file mode 100644 index 00000000..b0f0fd73 --- /dev/null +++ b/plugins/Cloudflare/v2/defaultContent/Account/accountZeroTrust.dash.json @@ -0,0 +1,798 @@ +{ + "name": "Account Zero Trust", + "schemaVersion": "1.5", + "timeframe": "none", + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "d7931877-849c-421d-88e5-c5a83d107ce4", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Gateway DNS Queries", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[gatewayDnsQueries]}}", + "name": "gatewayDnsQueries", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "resolverDecision" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "queryCount" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "queryCount_sum", + "comparisonColumn": "none", + "label": "Gateway DNS Queries" + } + } + } + } + }, + { + "i": "6d0c0f83-1c51-43b7-90f1-1ec4226b8d2a", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Gateway HTTP Requests", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[gatewayHttpRequests]}}", + "name": "gatewayHttpRequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "action" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "requests_sum", + "comparisonColumn": "none", + "label": "Gateway HTTP Requests" + } + } + } + } + }, + { + "i": "ac748a4a-ca7b-4b10-a2c0-50936b00e9d7", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Gateway Network Sessions", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[gatewayNetworkSessions]}}", + "name": "gatewayNetworkSessions", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "action" + }, + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sessionCount" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sessionCount_sum", + "comparisonColumn": "none", + "label": "Gateway Network Sessions" + } + } + } + } + }, + { + "i": "2edd6feb-b28c-455a-bb9b-8abdbbf04638", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Gateway DNS Queries by Decision", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[gatewayDnsQueries]}}", + "name": "gatewayDnsQueries", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "resolverDecision" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "queryCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "queryCount_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "queryCount_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "fab0220c-a177-4a16-8d9b-a9bb5ebbd0fb", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Top Gateway DNS Categories", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[gatewayDnsQueries]}}", + "name": "gatewayDnsQueries", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "categoryNames" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "queryCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "queryCount_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "queryCount_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "cb3540f5-b6f5-4596-9555-b9ee9a2b8792", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Gateway HTTP Requests Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[gatewayHttpRequests]}}", + "name": "gatewayHttpRequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "action" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "requests_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "daad39ca-4ae3-437e-a2a4-657f660e6045", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Gateway HTTP Requests by Action", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[gatewayHttpRequests]}}", + "name": "gatewayHttpRequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "action" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "requests_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "requests_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "7fe5da45-cb35-4c2b-98db-58e08a5bbbcd", + "x": 0, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Top Gateway Hosts", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[gatewayHttpRequests]}}", + "name": "gatewayHttpRequests", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "httpHost" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "requests" + ] + } + ] + }, + "sort": { + "by": [ + [ + "requests_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "requests_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "ae5e51c8-183b-4518-958e-422eafc1779e", + "x": 2, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Gateway Network Sessions by Action", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[gatewayNetworkSessions]}}", + "name": "gatewayNetworkSessions", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "action" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "sessionCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "sessionCount_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "sessionCount_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "36b11ab5-9da0-456f-8056-cfb27f386542", + "x": 0, + "y": 11, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "DNS Firewall Queries Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[dnsFirewallAnalytics]}}", + "name": "dnsFirewallAnalytics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "responseCode" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "queries" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "queries_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "876b9baa-c52d-4f4a-8cdd-8f8d5d490a58", + "x": 2, + "y": 11, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "DNS Firewall Queries by Response Code", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[dnsFirewallAnalytics]}}", + "name": "dnsFirewallAnalytics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "responseCode" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "queries" + ] + } + ] + }, + "sort": { + "by": [ + [ + "queries_sum", + "desc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Accounts]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Account]}}" + }, + "variables": [ + "{{variables.[Cloudflare Account]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "queries_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v2/defaultContent/Account/manifest.json b/plugins/Cloudflare/v2/defaultContent/Account/manifest.json new file mode 100644 index 00000000..935dfd77 --- /dev/null +++ b/plugins/Cloudflare/v2/defaultContent/Account/manifest.json @@ -0,0 +1,20 @@ +{ + "items": [ + { + "name": "account", + "type": "dashboard" + }, + { + "name": "accountResources", + "type": "dashboard" + }, + { + "name": "accountZeroTrust", + "type": "dashboard" + }, + { + "name": "accountDeveloperPlatform", + "type": "dashboard" + } + ] +} diff --git a/plugins/Cloudflare/v2/defaultContent/Core/account.dash.json b/plugins/Cloudflare/v2/defaultContent/Core/account.dash.json deleted file mode 100644 index c74e708c..00000000 --- a/plugins/Cloudflare/v2/defaultContent/Core/account.dash.json +++ /dev/null @@ -1,3249 +0,0 @@ -{ - "name": "Account", - "schemaVersion": "1.5", - "timeframe": "none", - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "dashboard": { - "_type": "layout/grid", - "columns": 4, - "version": 1, - "contents": [ - { - "i": "3bb95490-9698-407a-9dca-511995fe1ebb", - "x": 0, - "y": 0, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Workers", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[workerScripts]}}", - "name": "workerScripts", - "pluginConfigId": "{{configId}}", - "group": { - "by": [], - "aggregate": [ - { - "type": "count" - } - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "count", - "comparisonColumn": "none", - "label": "Workers" - } - } - } - } - }, - { - "i": "eb1d6ac1-f3e8-4935-a262-59e02fac22ad", - "x": 1, - "y": 0, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Pages Projects", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[pagesProjects]}}", - "name": "pagesProjects", - "pluginConfigId": "{{configId}}", - "group": { - "by": [], - "aggregate": [ - { - "type": "count" - } - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "count", - "comparisonColumn": "none", - "label": "Pages Projects" - } - } - } - } - }, - { - "i": "c206f73b-e9dd-4c97-8de6-153be439f5be", - "x": 2, - "y": 0, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Tunnels", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[tunnels]}}", - "name": "tunnels", - "pluginConfigId": "{{configId}}", - "group": { - "by": [], - "aggregate": [ - { - "type": "count" - } - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "count", - "comparisonColumn": "none", - "label": "Tunnels" - } - } - } - } - }, - { - "i": "7f158dbb-3a69-4c68-995e-756e6d6a7d07", - "x": 3, - "y": 0, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "R2 Buckets", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[r2Buckets]}}", - "name": "r2Buckets", - "pluginConfigId": "{{configId}}", - "group": { - "by": [], - "aggregate": [ - { - "type": "count" - } - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "count", - "comparisonColumn": "none", - "label": "R2 Buckets" - } - } - } - } - }, - { - "i": "fbb27de7-9d74-4de5-aed2-8b347947c7e5", - "x": 0, - "y": 2, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Account Details", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties" - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": true, - "hiddenColumns": [ - "id", - "label", - "link", - "links", - "sourceId", - "sourceName", - "type" - ] - } - } - } - } - }, - { - "i": "041c7858-722a-4e36-9e17-fa44ab609ea1", - "x": 2, - "y": 2, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Tunnels", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[tunnels]}}", - "name": "tunnels", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "tunnelName", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "tunnelName", - "stateColumn": "status", - "sublabel": "tunnelType", - "linkColumn": "tunnelName", - "columns": 2 - } - } - } - } - }, - { - "i": "5c67e20d-99f0-4dab-b8c6-13a5f0fdf92b", - "x": 0, - "y": 5, - "w": 2, - "h": 4, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Workers", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[workerScripts]}}", - "name": "workerScripts", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "scriptName", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": false, - "columnOrder": [ - "scriptName", - "usageModel", - "handlers", - "placementMode", - "modifiedOn" - ], - "hiddenColumns": [ - "sourceId", - "accountId", - "logpush", - "createdOn" - ] - } - } - } - } - }, - { - "i": "075c1543-3d1f-4d74-a658-dc6e19575764", - "x": 2, - "y": 5, - "w": 2, - "h": 4, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Pages Projects", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[pagesProjects]}}", - "name": "pagesProjects", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "projectName", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": false, - "columnOrder": [ - "projectName", - "latestDeploymentStatus", - "productionBranch", - "domains", - "latestDeploymentOn" - ], - "hiddenColumns": [ - "sourceId", - "accountId", - "subdomain", - "createdOn" - ] - } - } - } - } - }, - { - "i": "7b5a1c5b-ad5d-4cee-b6fa-4210171976e8", - "x": 0, - "y": 9, - "w": 2, - "h": 4, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "R2 Buckets", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[r2Buckets]}}", - "name": "r2Buckets", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "bucketName", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": false, - "columnOrder": [ - "bucketName", - "location", - "storageClass", - "createdOn" - ], - "hiddenColumns": [ - "sourceId", - "accountId" - ] - } - } - } - } - }, - { - "i": "65d57e58-56be-42b5-86cc-735ef92fa7d8", - "x": 2, - "y": 9, - "w": 2, - "h": 4, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "KV Namespaces", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[kvNamespaces]}}", - "name": "kvNamespaces", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "namespaceTitle", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": false, - "columnOrder": [ - "namespaceTitle", - "supportsUrlEncoding" - ], - "hiddenColumns": [ - "sourceId", - "accountId" - ] - } - } - } - } - }, - { - "i": "70461624-c21e-4501-9244-23a15edd4add", - "x": 0, - "y": 13, - "w": 2, - "h": 4, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "D1 Databases", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[d1Databases]}}", - "name": "d1Databases", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "databaseName", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": false, - "columnOrder": [ - "databaseName", - "numTables", - "fileSize", - "version", - "createdOn" - ], - "hiddenColumns": [ - "sourceId", - "accountId" - ] - } - } - } - } - }, - { - "i": "c25cb5ba-cd50-4a90-8871-b99f8c57bcf7", - "x": 2, - "y": 13, - "w": 2, - "h": 4, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Queues", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[queues]}}", - "name": "queues", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "queueName", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": false, - "columnOrder": [ - "queueName", - "producers", - "consumers", - "modifiedOn" - ], - "hiddenColumns": [ - "sourceId", - "accountId", - "createdOn" - ] - } - } - } - } - }, - { - "i": "cd0f4644-c131-45c5-aef2-0ec8d91ca62e", - "x": 0, - "y": 17, - "w": 2, - "h": 4, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Load Balancer Pools", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[loadBalancerPools]}}", - "name": "loadBalancerPools", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "poolName", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": false, - "columnOrder": [ - "poolName", - "enabled", - "originCount", - "minimumOrigins", - "modifiedOn" - ], - "hiddenColumns": [ - "sourceId", - "accountId", - "monitorId", - "createdOn" - ] - } - } - } - } - }, - { - "i": "f342d86a-84d2-4dec-999c-ef0c39f94870", - "x": 2, - "y": 17, - "w": 2, - "h": 4, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Access Applications", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[accessApps]}}", - "name": "accessApps", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "appName", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": false, - "columnOrder": [ - "appName", - "appType", - "domain", - "sessionDuration", - "appLauncherVisible" - ], - "hiddenColumns": [ - "sourceId", - "accountId", - "createdOn", - "modifiedOn" - ] - } - } - } - } - }, - { - "i": "83f57d60-3e02-40dd-8ab5-9ca6bed4fea9", - "x": 0, - "y": 21, - "w": 2, - "h": 4, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Durable Object Namespaces", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[durableObjectNamespaces]}}", - "name": "durableObjectNamespaces", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "namespaceName", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": false, - "columnOrder": [ - "namespaceName", - "scriptName", - "className", - "usesSqlite" - ], - "hiddenColumns": [ - "sourceId", - "accountId" - ] - } - } - } - } - }, - { - "i": "2336e698-182b-4dc7-83bf-5d104c88eead", - "x": 2, - "y": 21, - "w": 2, - "h": 4, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Vectorize Indexes", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[vectorizeIndexes]}}", - "name": "vectorizeIndexes", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "indexName", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": false, - "columnOrder": [ - "indexName", - "dimensions", - "metric", - "createdOn" - ], - "hiddenColumns": [ - "sourceId", - "accountId", - "modifiedOn" - ] - } - } - } - } - }, - { - "i": "7c8fd8d9-542a-4665-9621-e7ed1b8583b7", - "x": 0, - "y": 25, - "w": 2, - "h": 4, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Hyperdrive Configs", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[hyperdriveConfigs]}}", - "name": "hyperdriveConfigs", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "configName", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": false, - "columnOrder": [ - "configName", - "database", - "host", - "scheme" - ], - "hiddenColumns": [ - "sourceId", - "accountId", - "cachingDisabled" - ] - } - } - } - } - }, - { - "i": "d7931877-849c-421d-88e5-c5a83d107ce4", - "x": 0, - "y": 29, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Gateway DNS Queries", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[gatewayDnsQueries]}}", - "name": "gatewayDnsQueries", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "resolverDecision" - }, - "group": { - "by": [], - "aggregate": [ - { - "type": "sum", - "names": [ - "queryCount" - ] - } - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "queryCount_sum", - "comparisonColumn": "none", - "label": "Gateway DNS Queries" - } - } - } - } - }, - { - "i": "6d0c0f83-1c51-43b7-90f1-1ec4226b8d2a", - "x": 1, - "y": 29, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Gateway HTTP Requests", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[gatewayHttpRequests]}}", - "name": "gatewayHttpRequests", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "action" - }, - "group": { - "by": [], - "aggregate": [ - { - "type": "sum", - "names": [ - "requests" - ] - } - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "requests_sum", - "comparisonColumn": "none", - "label": "Gateway HTTP Requests" - } - } - } - } - }, - { - "i": "0e7ae631-b894-4f67-a73a-b9e61ce540f9", - "x": 2, - "y": 29, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "AI Inference Requests", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[workersAiInference]}}", - "name": "workersAiInference", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "modelId" - }, - "group": { - "by": [], - "aggregate": [ - { - "type": "sum", - "names": [ - "requests" - ] - } - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "requests_sum", - "comparisonColumn": "none", - "label": "AI Inference Requests" - } - } - } - } - }, - { - "i": "685debee-fe22-4057-be74-f16010314596", - "x": 3, - "y": 29, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "AI Output Tokens", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[workersAiInference]}}", - "name": "workersAiInference", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "modelId" - }, - "group": { - "by": [], - "aggregate": [ - { - "type": "sum", - "names": [ - "outputTokens" - ] - } - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "outputTokens_sum", - "comparisonColumn": "none", - "label": "AI Output Tokens" - } - } - } - } - }, - { - "i": "2edd6feb-b28c-455a-bb9b-8abdbbf04638", - "x": 0, - "y": 31, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Gateway DNS Queries by Decision", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[gatewayDnsQueries]}}", - "name": "gatewayDnsQueries", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "resolverDecision" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "queryCount" - ] - } - ] - }, - "sort": { - "by": [ - [ - "queryCount_sum", - "desc" - ] - ], - "top": 10 - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-donut-chart", - "config": { - "data-stream-donut-chart": { - "valueColumn": "queryCount_sum", - "labelColumn": "breakdown_uniqueValues", - "hideCenterValue": false, - "showValuesAsPercentage": false, - "legendPosition": "auto", - "legendMode": "table" - } - } - } - } - }, - { - "i": "fab0220c-a177-4a16-8d9b-a9bb5ebbd0fb", - "x": 2, - "y": 31, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Top Gateway DNS Categories", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[gatewayDnsQueries]}}", - "name": "gatewayDnsQueries", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "categoryNames" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "queryCount" - ] - } - ] - }, - "sort": { - "by": [ - [ - "queryCount_sum", - "desc" - ] - ], - "top": 10 - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-bar-chart", - "config": { - "data-stream-bar-chart": { - "xAxisData": "breakdown_uniqueValues", - "yAxisData": [ - "queryCount_sum" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "vertical", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } - } - } - } - } - }, - { - "i": "daad39ca-4ae3-437e-a2a4-657f660e6045", - "x": 0, - "y": 34, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Gateway HTTP Requests by Action", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[gatewayHttpRequests]}}", - "name": "gatewayHttpRequests", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "action" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "requests" - ] - } - ] - }, - "sort": { - "by": [ - [ - "requests_sum", - "desc" - ] - ], - "top": 10 - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-donut-chart", - "config": { - "data-stream-donut-chart": { - "valueColumn": "requests_sum", - "labelColumn": "breakdown_uniqueValues", - "hideCenterValue": false, - "showValuesAsPercentage": false, - "legendPosition": "auto", - "legendMode": "table" - } - } - } - } - }, - { - "i": "7fe5da45-cb35-4c2b-98db-58e08a5bbbcd", - "x": 2, - "y": 34, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Top Gateway Hosts", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[gatewayHttpRequests]}}", - "name": "gatewayHttpRequests", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "httpHost" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "requests" - ] - } - ] - }, - "sort": { - "by": [ - [ - "requests_sum", - "desc" - ] - ], - "top": 10 - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-bar-chart", - "config": { - "data-stream-bar-chart": { - "xAxisData": "breakdown_uniqueValues", - "yAxisData": [ - "requests_sum" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "vertical", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } - } - } - } - } - }, - { - "i": "ac748a4a-ca7b-4b10-a2c0-50936b00e9d7", - "x": 0, - "y": 37, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Gateway Network Sessions", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[gatewayNetworkSessions]}}", - "name": "gatewayNetworkSessions", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "action" - }, - "group": { - "by": [], - "aggregate": [ - { - "type": "sum", - "names": [ - "sessionCount" - ] - } - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "sessionCount_sum", - "comparisonColumn": "none", - "label": "Gateway Network Sessions" - } - } - } - } - }, - { - "i": "ae5e51c8-183b-4518-958e-422eafc1779e", - "x": 0, - "y": 39, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Gateway Network Sessions by Action", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[gatewayNetworkSessions]}}", - "name": "gatewayNetworkSessions", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "action" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "sessionCount" - ] - } - ] - }, - "sort": { - "by": [ - [ - "sessionCount_sum", - "desc" - ] - ], - "top": 10 - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-donut-chart", - "config": { - "data-stream-donut-chart": { - "valueColumn": "sessionCount_sum", - "labelColumn": "breakdown_uniqueValues", - "hideCenterValue": false, - "showValuesAsPercentage": false, - "legendPosition": "auto", - "legendMode": "table" - } - } - } - } - }, - { - "i": "cb3540f5-b6f5-4596-9555-b9ee9a2b8792", - "x": 0, - "y": 42, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Gateway HTTP Requests Over Time", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[gatewayHttpRequests]}}", - "name": "gatewayHttpRequests", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "action" - }, - "group": { - "by": [ - [ - "date", - "byDay" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "requests" - ] - } - ] - }, - "sort": { - "by": [ - [ - "date_byDay", - "asc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "date_byDay", - "yAxisColumn": [ - "requests_sum" - ], - "seriesColumn": "none", - "showLegend": false, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "6ebe2742-9444-4be7-9edc-1c5b1e113633", - "x": 2, - "y": 42, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Workers AI Requests by Model", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[workersAiInference]}}", - "name": "workersAiInference", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "modelId" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "requests" - ] - } - ] - }, - "sort": { - "by": [ - [ - "requests_sum", - "desc" - ] - ], - "top": 10 - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-bar-chart", - "config": { - "data-stream-bar-chart": { - "xAxisData": "breakdown_uniqueValues", - "yAxisData": [ - "requests_sum" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "vertical", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } - } - } - } - } - }, - { - "i": "e3b25cc5-489a-4604-96ce-d49e3ee5b6e6", - "x": 0, - "y": 45, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Workers AI Token Usage", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[workersAiInference]}}", - "name": "workersAiInference", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "modelId" - }, - "group": { - "by": [ - [ - "date", - "byDay" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "inputTokens" - ] - }, - { - "type": "sum", - "names": [ - "outputTokens" - ] - } - ] - }, - "sort": { - "by": [ - [ - "date_byDay", - "asc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "date_byDay", - "yAxisColumn": [ - "inputTokens_sum", - "outputTokens_sum" - ], - "seriesColumn": "none", - "showLegend": true, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "2d7e5b1b-394e-4111-91de-2aa319f7fea8", - "x": 2, - "y": 45, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Workers AI Inference Time", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[workersAiInference]}}", - "name": "workersAiInference", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "modelId" - }, - "group": { - "by": [ - [ - "date", - "byDay" - ] - ], - "aggregate": [ - { - "type": "mean", - "names": [ - "avgDurationMs" - ] - } - ] - }, - "sort": { - "by": [ - [ - "date_byDay", - "asc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "date_byDay", - "yAxisColumn": [ - "avgDurationMs_mean" - ], - "seriesColumn": "none", - "showLegend": false, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "a38a89d8-b533-4bef-bbbb-3bfefb3f44ba", - "x": 0, - "y": 48, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Audit Log Actions", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[auditLogs]}}", - "name": "auditLogs", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "actionType" - }, - "group": { - "by": [], - "aggregate": [ - { - "type": "sum", - "names": [ - "actionCount" - ] - } - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "actionCount_sum", - "comparisonColumn": "none", - "label": "Audit Log Actions" - } - } - } - } - }, - { - "i": "885088db-eba0-4a67-a170-c12c84b61c3c", - "x": 1, - "y": 48, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Image Requests", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[imagesRequests]}}", - "name": "imagesRequests", - "pluginConfigId": "{{configId}}", - "group": { - "by": [], - "aggregate": [ - { - "type": "sum", - "names": [ - "requests" - ] - } - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "requests_sum", - "comparisonColumn": "none", - "label": "Image Requests" - } - } - } - } - }, - { - "i": "33b7c30d-8dea-42a1-96d8-a885c9119f0a", - "x": 2, - "y": 48, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Image Transformations", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[imagesTransformations]}}", - "name": "imagesTransformations", - "pluginConfigId": "{{configId}}", - "group": { - "by": [], - "aggregate": [ - { - "type": "sum", - "names": [ - "transformations" - ] - } - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "transformations_sum", - "comparisonColumn": "none", - "label": "Image Transformations" - } - } - } - } - }, - { - "i": "b6731e3d-91a3-4ead-9685-7df79e235ce0", - "x": 3, - "y": 48, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Pages Function Requests", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[pagesFunctionsInvocations]}}", - "name": "pagesFunctionsInvocations", - "pluginConfigId": "{{configId}}", - "group": { - "by": [], - "aggregate": [ - { - "type": "sum", - "names": [ - "sum.requests" - ] - } - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "sum.requests_sum", - "comparisonColumn": "none", - "label": "Pages Function Requests" - } - } - } - } - }, - { - "i": "463aafc7-e7fe-483a-9415-135d591794ab", - "x": 0, - "y": 50, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Audit Log Actions Over Time", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[auditLogs]}}", - "name": "auditLogs", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "actionType" - }, - "group": { - "by": [ - [ - "date", - "byDay" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "actionCount" - ] - } - ] - }, - "sort": { - "by": [ - [ - "date_byDay", - "asc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "date_byDay", - "yAxisColumn": [ - "actionCount_sum" - ], - "seriesColumn": "none", - "showLegend": false, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "b674edbe-1b30-41b5-a4fa-08bf7ad4ffb5", - "x": 2, - "y": 50, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Top Audit Log Actions", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[auditLogs]}}", - "name": "auditLogs", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "actionType" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "actionCount" - ] - } - ] - }, - "sort": { - "by": [ - [ - "actionCount_sum", - "desc" - ] - ], - "top": 10 - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-bar-chart", - "config": { - "data-stream-bar-chart": { - "xAxisData": "breakdown_uniqueValues", - "yAxisData": [ - "actionCount_sum" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "vertical", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } - } - } - } - } - }, - { - "i": "ed67a1f0-321c-48e0-98da-937932cbe709", - "x": 0, - "y": 53, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Image Requests Over Time", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[imagesRequests]}}", - "name": "imagesRequests", - "pluginConfigId": "{{configId}}", - "group": { - "by": [ - [ - "date", - "byDay" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "requests" - ] - } - ] - }, - "sort": { - "by": [ - [ - "date_byDay", - "asc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "date_byDay", - "yAxisColumn": [ - "requests_sum" - ], - "seriesColumn": "none", - "showLegend": false, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "f1b12eaa-907d-4268-8481-fad2f24f707a", - "x": 2, - "y": 53, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Image Transformations Over Time", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[imagesTransformations]}}", - "name": "imagesTransformations", - "pluginConfigId": "{{configId}}", - "group": { - "by": [ - [ - "date", - "byDay" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "transformations" - ] - } - ] - }, - "sort": { - "by": [ - [ - "date_byDay", - "asc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "date_byDay", - "yAxisColumn": [ - "transformations_sum" - ], - "seriesColumn": "none", - "showLegend": false, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "a43ecf79-6372-4f65-bec5-d9e8c925d643", - "x": 0, - "y": 56, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Pages Functions Requests and Errors", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[pagesFunctionsInvocations]}}", - "name": "pagesFunctionsInvocations", - "pluginConfigId": "{{configId}}", - "group": { - "by": [ - [ - "dimensions.datetime", - "byDay" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "sum.requests" - ] - }, - { - "type": "sum", - "names": [ - "sum.errors" - ] - } - ] - }, - "sort": { - "by": [ - [ - "dimensions.datetime_byDay", - "asc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "dimensions.datetime_byDay", - "yAxisColumn": [ - "sum.requests_sum", - "sum.errors_sum" - ], - "seriesColumn": "none", - "showLegend": true, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "76b7293c-87ef-41eb-97c3-3633f59732de", - "x": 2, - "y": 56, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Top Pages Functions by Requests", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[pagesFunctionsInvocations]}}", - "name": "pagesFunctionsInvocations", - "pluginConfigId": "{{configId}}", - "group": { - "by": [ - [ - "dimensions.scriptName", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "sum.requests" - ] - } - ] - }, - "sort": { - "by": [ - [ - "sum.requests_sum", - "desc" - ] - ], - "top": 10 - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-bar-chart", - "config": { - "data-stream-bar-chart": { - "xAxisData": "dimensions.scriptName_uniqueValues", - "yAxisData": [ - "sum.requests_sum" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "vertical", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } - } - } - } - } - }, - { - "i": "18fdde70-9cd8-4d1b-8b5c-0b06ccd397cd", - "x": 0, - "y": 59, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Browser Rendering Session Duration", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[browserRendering]}}", - "name": "browserRendering", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "clientLibrary" - }, - "group": { - "by": [ - [ - "date", - "byDay" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "durationMs" - ] - } - ] - }, - "sort": { - "by": [ - [ - "date_byDay", - "asc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "date_byDay", - "yAxisColumn": [ - "durationMs_sum" - ], - "seriesColumn": "none", - "showLegend": false, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "b7a3742d-41bb-42f0-8588-22ae18ba6cc3", - "x": 2, - "y": 59, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Browser Rendering Sessions by Client Library", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[browserRendering]}}", - "name": "browserRendering", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "clientLibrary" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "distinctCount", - "names": [ - "sessionId" - ] - } - ] - }, - "sort": { - "by": [ - [ - "sessionId_distinctCount", - "desc" - ] - ], - "top": 10 - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-bar-chart", - "config": { - "data-stream-bar-chart": { - "xAxisData": "breakdown_uniqueValues", - "yAxisData": [ - "sessionId_distinctCount" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "vertical", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } - } - } - } - } - }, - { - "i": "36b11ab5-9da0-456f-8056-cfb27f386542", - "x": 0, - "y": 62, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "DNS Firewall Queries Over Time", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[dnsFirewallAnalytics]}}", - "name": "dnsFirewallAnalytics", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "responseCode" - }, - "group": { - "by": [ - [ - "date", - "byDay" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "queries" - ] - } - ] - }, - "sort": { - "by": [ - [ - "date_byDay", - "asc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "date_byDay", - "yAxisColumn": [ - "queries_sum" - ], - "seriesColumn": "none", - "showLegend": false, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "876b9baa-c52d-4f4a-8cdd-8f8d5d490a58", - "x": 2, - "y": 62, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "DNS Firewall Queries by Response Code", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[dnsFirewallAnalytics]}}", - "name": "dnsFirewallAnalytics", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "responseCode" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "queries" - ] - } - ] - }, - "sort": { - "by": [ - [ - "queries_sum", - "desc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-donut-chart", - "config": { - "data-stream-donut-chart": { - "valueColumn": "queries_sum", - "labelColumn": "breakdown_uniqueValues", - "hideCenterValue": false, - "showValuesAsPercentage": false, - "legendPosition": "auto", - "legendMode": "table" - } - } - } - } - }, - { - "i": "36f99add-606b-4848-8e56-7dfdf94c824b", - "x": 0, - "y": 65, - "w": 4, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Requests by Zone", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[accountTraffic]}}", - "name": "accountTraffic", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "zoneTag" - }, - "sort": { - "by": [ - [ - "datetime", - "asc" - ] - ] - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "datetime", - "yAxisColumn": [ - "requests" - ], - "seriesColumn": "zoneName", - "showLegend": true, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - }, - "timeframe": "last24hours" - } - }, - { - "i": "2789dab8-bd9d-4cf9-b5d4-9e1ed480084f", - "x": 0, - "y": 68, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Traffic by Country", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[accountTraffic]}}", - "name": "accountTraffic", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "clientCountryName" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "requests" - ] - } - ] - }, - "sort": { - "by": [ - [ - "requests_sum", - "desc" - ] - ], - "top": 10 - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-bar-chart", - "config": { - "data-stream-bar-chart": { - "xAxisData": "breakdown_uniqueValues", - "yAxisData": [ - "requests_sum" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "horizontal", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } - } - } - }, - "timeframe": "last24hours" - } - }, - { - "i": "8eb403cb-7ab9-46b2-84df-2aa0ed1c22ca", - "x": 2, - "y": 68, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Traffic by Status Code", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[accountTraffic]}}", - "name": "accountTraffic", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "edgeResponseStatus" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "requests" - ] - } - ] - }, - "sort": { - "by": [ - [ - "requests_sum", - "desc" - ] - ], - "top": 10 - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-bar-chart", - "config": { - "data-stream-bar-chart": { - "xAxisData": "breakdown_uniqueValues", - "yAxisData": [ - "requests_sum" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "horizontal", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } - } - } - }, - "timeframe": "last24hours" - } - }, - { - "i": "a92b1e43-9903-4d5d-9941-6dd4c1e7f726", - "x": 0, - "y": 71, - "w": 4, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Workers Build Minutes", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[workerBuildMinutes]}}", - "name": "workerBuildMinutes", - "pluginConfigId": "{{configId}}", - "group": { - "by": [ - [ - "dimensions.datetime", - "byDay" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "sum.buildMinutes" - ] - } - ] - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Accounts]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Account]}}" - }, - "variables": [ - "{{variables.[Cloudflare Account]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "dimensions.datetime_byDay", - "yAxisColumn": [ - "sum.buildMinutes_sum" - ], - "seriesColumn": "none", - "showLegend": false, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - }, - "timeframe": "last30days" - } - } - ] - } -} diff --git a/plugins/Cloudflare/v2/defaultContent/Core/manifest.json b/plugins/Cloudflare/v2/defaultContent/Core/manifest.json deleted file mode 100644 index 7b59b59d..00000000 --- a/plugins/Cloudflare/v2/defaultContent/Core/manifest.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "items": [ - { - "name": "account", - "type": "dashboard" - }, - { - "name": "zone", - "type": "dashboard" - } - ] -} diff --git a/plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json b/plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json deleted file mode 100644 index 4e07a502..00000000 --- a/plugins/Cloudflare/v2/defaultContent/Core/zone.dash.json +++ /dev/null @@ -1,3123 +0,0 @@ -{ - "name": "Zone", - "schemaVersion": "1.5", - "timeframe": "last24hours", - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "dashboard": { - "_type": "layout/grid", - "columns": 4, - "version": 1, - "contents": [ - { - "i": "dbbd193c-5a10-4b49-8a2b-f33b1fe54efe", - "x": 0, - "y": 0, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Requests", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneTraffic]}}", - "name": "zoneTraffic", - "pluginConfigId": "{{configId}}", - "group": { - "by": [], - "aggregate": [ - { - "type": "sum", - "names": [ - "sum.requests" - ] - } - ] - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "sum.requests_sum", - "comparisonColumn": "none", - "label": "Requests" - } - } - } - } - }, - { - "i": "359ed863-1182-4dea-8299-3ed8a3b75b22", - "x": 1, - "y": 0, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Unique Visitors", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneTraffic]}}", - "name": "zoneTraffic", - "pluginConfigId": "{{configId}}", - "group": { - "by": [], - "aggregate": [ - { - "type": "sum", - "names": [ - "uniq.uniques" - ] - } - ] - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "uniq.uniques_sum", - "comparisonColumn": "none", - "label": "Unique Visitors" - } - } - } - } - }, - { - "i": "1cac5d62-0609-4166-9ead-ba20f448f830", - "x": 2, - "y": 0, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Bandwidth", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneTraffic]}}", - "name": "zoneTraffic", - "pluginConfigId": "{{configId}}", - "group": { - "by": [], - "aggregate": [ - { - "type": "sum", - "names": [ - "sum.bytes" - ] - } - ] - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "sum.bytes_sum", - "comparisonColumn": "none", - "label": "Bandwidth" - } - } - } - } - }, - { - "i": "2d0590e9-4c6b-460d-8919-c2658524e750", - "x": 3, - "y": 0, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Threats", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneTraffic]}}", - "name": "zoneTraffic", - "pluginConfigId": "{{configId}}", - "group": { - "by": [], - "aggregate": [ - { - "type": "sum", - "names": [ - "sum.threats" - ] - } - ] - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "sum.threats_sum", - "comparisonColumn": "none", - "label": "Threats" - } - } - } - } - }, - { - "i": "a73efcb0-71d7-4148-91c5-56edd3518568", - "x": 0, - "y": 2, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Zone Details", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties" - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": true, - "hiddenColumns": [ - "id", - "label", - "link", - "links", - "sourceId", - "sourceName", - "type" - ] - } - } - } - } - }, - { - "i": "4b177d07-939f-4a35-9b5b-d47d7cad13c8", - "x": 2, - "y": 2, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Requests", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneTraffic]}}", - "name": "zoneTraffic", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "dimensions.datetime", - "asc" - ] - ] - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "dimensions.datetime", - "yAxisColumn": [ - "sum.requests", - "sum.cachedRequests" - ], - "seriesColumn": "none", - "showLegend": true, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "2b949c2a-6bd1-480b-8b02-78ae669d7be4", - "x": 0, - "y": 5, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Bandwidth", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneTraffic]}}", - "name": "zoneTraffic", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "dimensions.datetime", - "asc" - ] - ] - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "dimensions.datetime", - "yAxisColumn": [ - "sum.bytes", - "sum.cachedBytes" - ], - "seriesColumn": "none", - "showLegend": true, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "2ce8c81d-92e5-4e30-b1fb-95a45e1c567d", - "x": 2, - "y": 5, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Cache Hit Ratio", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneTraffic]}}", - "name": "zoneTraffic", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "dimensions.datetime", - "asc" - ] - ] - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "dimensions.datetime", - "yAxisColumn": [ - "cacheHitRatio" - ], - "seriesColumn": "none", - "showLegend": false, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "8a7c2e43-e5a1-4fb8-a862-3bf8ec9f364d", - "x": 0, - "y": 8, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Traffic by Country", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneTrafficBreakdown]}}", - "name": "zoneTrafficBreakdown", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "clientCountryName" - }, - "sort": { - "by": [ - [ - "requests", - "desc" - ] - ], - "top": 10 - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-bar-chart", - "config": { - "data-stream-bar-chart": { - "xAxisData": "breakdown", - "yAxisData": [ - "requests" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "vertical", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } - } - } - } - } - }, - { - "i": "babb40cf-e759-4887-8474-8649bfc1a846", - "x": 2, - "y": 8, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Traffic by Status Code", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneTrafficBreakdown]}}", - "name": "zoneTrafficBreakdown", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "edgeResponseStatus" - }, - "sort": { - "by": [ - [ - "requests", - "desc" - ] - ], - "top": 10 - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-donut-chart", - "config": { - "data-stream-donut-chart": { - "valueColumn": "requests", - "labelColumn": "breakdown", - "hideCenterValue": false, - "showValuesAsPercentage": false, - "legendPosition": "auto", - "legendMode": "table" - } - } - } - } - }, - { - "i": "5c613d78-1252-432a-b699-9064fe5625bc", - "x": 0, - "y": 11, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Cache Status", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneTrafficBreakdown]}}", - "name": "zoneTrafficBreakdown", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "cacheStatus" - }, - "sort": { - "by": [ - [ - "requests", - "desc" - ] - ] - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-donut-chart", - "config": { - "data-stream-donut-chart": { - "valueColumn": "requests", - "labelColumn": "breakdown", - "hideCenterValue": false, - "showValuesAsPercentage": false, - "legendPosition": "auto", - "legendMode": "table" - } - } - } - } - }, - { - "i": "fb685bc2-f0f1-4d13-b965-4852d361d7bc", - "x": 2, - "y": 11, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Traffic by Device Type", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneTrafficBreakdown]}}", - "name": "zoneTrafficBreakdown", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "clientDeviceType" - }, - "sort": { - "by": [ - [ - "requests", - "desc" - ] - ] - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-donut-chart", - "config": { - "data-stream-donut-chart": { - "valueColumn": "requests", - "labelColumn": "breakdown", - "hideCenterValue": false, - "showValuesAsPercentage": false, - "legendPosition": "auto", - "legendMode": "table" - } - } - } - } - }, - { - "i": "414ccb22-cce5-4121-ba54-ba0c4ae80aa8", - "x": 0, - "y": 14, - "w": 4, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Firewall Events (Last 30 Days)", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneFirewallEventVolume]}}", - "name": "zoneFirewallEventVolume", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "datetime", - "asc" - ] - ] - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "timeframe": "last30days", - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "datetime", - "yAxisColumn": [ - "events" - ], - "seriesColumn": "zoneName", - "showLegend": false, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "b5b428c0-6e8b-4b20-8637-826523d8875e", - "x": 0, - "y": 17, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Firewall Events by Rule", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneFirewallEvents]}}", - "name": "zoneFirewallEvents", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "ruleId" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "events" - ] - } - ] - }, - "sort": { - "by": [ - [ - "events_sum", - "desc" - ] - ], - "top": 10 - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-bar-chart", - "config": { - "data-stream-bar-chart": { - "xAxisData": "breakdown_uniqueValues", - "yAxisData": [ - "events_sum" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "vertical", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } - } - } - } - } - }, - { - "i": "f70d4a4d-aa25-436e-bc2d-f57913923742", - "x": 2, - "y": 17, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Firewall Events by Service", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneFirewallEvents]}}", - "name": "zoneFirewallEvents", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "source" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "events" - ] - } - ] - }, - "sort": { - "by": [ - [ - "events_sum", - "desc" - ] - ] - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-donut-chart", - "config": { - "data-stream-donut-chart": { - "valueColumn": "events_sum", - "labelColumn": "breakdown_uniqueValues", - "hideCenterValue": false, - "showValuesAsPercentage": false, - "legendPosition": "auto", - "legendMode": "table" - } - } - } - } - }, - { - "i": "ab07298c-beb2-45ad-ab55-973b5ee13c9e", - "x": 0, - "y": 20, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Firewall Events by Country", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneFirewallEvents]}}", - "name": "zoneFirewallEvents", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "clientCountryName" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "events" - ] - } - ] - }, - "sort": { - "by": [ - [ - "events_sum", - "desc" - ] - ], - "top": 10 - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-bar-chart", - "config": { - "data-stream-bar-chart": { - "xAxisData": "breakdown_uniqueValues", - "yAxisData": [ - "events_sum" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "vertical", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } - } - } - } - } - }, - { - "i": "36980a5b-9966-4da8-b4ae-03a64c40c648", - "x": 2, - "y": 20, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Firewall Actions", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneFirewallEvents]}}", - "name": "zoneFirewallEvents", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "source" - }, - "group": { - "by": [ - [ - "action", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "events" - ] - } - ] - }, - "sort": { - "by": [ - [ - "events_sum", - "desc" - ] - ] - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-donut-chart", - "config": { - "data-stream-donut-chart": { - "valueColumn": "events_sum", - "labelColumn": "action_uniqueValues", - "hideCenterValue": false, - "showValuesAsPercentage": false, - "legendPosition": "auto", - "legendMode": "table" - } - } - } - } - }, - { - "i": "6084f30d-d547-4fdf-8712-6ac71b5fb03a", - "x": 0, - "y": 23, - "w": 2, - "h": 4, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "SSL Certificates", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneCertificates]}}", - "name": "zoneCertificates", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "daysUntilExpiry", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": false, - "columnOrder": [ - "hosts", - "status", - "daysUntilExpiry", - "expiresOn", - "certificateAuthority", - "type" - ], - "hiddenColumns": [ - "id", - "issuer", - "validationMethod" - ] - } - } - } - } - }, - { - "i": "b32501ab-3b1e-47da-bb9c-19fab121891f", - "x": 2, - "y": 23, - "w": 2, - "h": 4, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Health Checks", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneHealthChecks]}}", - "name": "zoneHealthChecks", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": false, - "columnOrder": [ - "name", - "status", - "address", - "type", - "failure_reason", - "suspended" - ], - "hiddenColumns": [ - "id", - "interval", - "timeout", - "consecutive_fails", - "consecutive_successes", - "check_regions", - "created_on", - "modified_on" - ] - } - } - } - } - }, - { - "i": "2a5caeac-bbae-4322-934c-4a58f34091f0", - "x": 0, - "y": 27, - "w": 4, - "h": 4, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "DNS Records", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneDnsRecords]}}", - "name": "zoneDnsRecords", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": false, - "columnOrder": [ - "name", - "type", - "content", - "proxied", - "ttl", - "comment" - ], - "hiddenColumns": [ - "id", - "tags", - "created_on", - "modified_on" - ] - } - } - } - } - }, - { - "i": "4340f0d4-7cb2-495e-a086-4b115ac7eede", - "x": 0, - "y": 31, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Load Balancing by Pool", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneLoadBalancing]}}", - "name": "zoneLoadBalancing", - "pluginConfigId": "{{configId}}", - "group": { - "by": [ - [ - "dimensions.selectedPoolName", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "count" - ] - } - ] - }, - "sort": { - "by": [ - [ - "count_sum", - "desc" - ] - ], - "top": 10 - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-bar-chart", - "config": { - "data-stream-bar-chart": { - "xAxisData": "dimensions.selectedPoolName_uniqueValues", - "yAxisData": [ - "count_sum" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "vertical", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } - } - } - } - } - }, - { - "i": "d0c74ae9-3aca-4708-a4a1-373db8a88696", - "x": 2, - "y": 31, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Load Balancing by Origin", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneLoadBalancing]}}", - "name": "zoneLoadBalancing", - "pluginConfigId": "{{configId}}", - "group": { - "by": [ - [ - "dimensions.selectedOriginName", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "count" - ] - } - ] - }, - "sort": { - "by": [ - [ - "count_sum", - "desc" - ] - ], - "top": 10 - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-bar-chart", - "config": { - "data-stream-bar-chart": { - "xAxisData": "dimensions.selectedOriginName_uniqueValues", - "yAxisData": [ - "count_sum" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "vertical", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } - } - } - } - } - }, - { - "i": "99e46b39-b7fd-4d39-8990-7bfec62f4a92", - "x": 0, - "y": 34, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "LCP (P75)", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[rumWebVitals]}}", - "name": "rumWebVitals", - "pluginConfigId": "{{configId}}", - "group": { - "by": [], - "aggregate": [ - { - "type": "mean", - "names": [ - "largestContentfulPaintP75" - ] - } - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "largestContentfulPaintP75_mean", - "comparisonColumn": "none", - "label": "LCP (P75)" - } - } - } - } - }, - { - "i": "5817c6a0-7759-4c3a-93a8-dfce7f44fc97", - "x": 1, - "y": 34, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "INP (P75)", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[rumWebVitals]}}", - "name": "rumWebVitals", - "pluginConfigId": "{{configId}}", - "group": { - "by": [], - "aggregate": [ - { - "type": "mean", - "names": [ - "interactionToNextPaintP75" - ] - } - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "interactionToNextPaintP75_mean", - "comparisonColumn": "none", - "label": "INP (P75)" - } - } - } - } - }, - { - "i": "3681fbe9-0fb2-449b-85c3-f66e81c37fe3", - "x": 2, - "y": 34, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "CLS (P75)", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[rumWebVitals]}}", - "name": "rumWebVitals", - "pluginConfigId": "{{configId}}", - "group": { - "by": [], - "aggregate": [ - { - "type": "mean", - "names": [ - "cumulativeLayoutShiftP75" - ] - } - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "cumulativeLayoutShiftP75_mean", - "comparisonColumn": "none", - "label": "CLS (P75)" - } - } - } - } - }, - { - "i": "865ade66-66ea-441f-a6d0-27a3d8a7f26d", - "x": 3, - "y": 34, - "w": 1, - "h": 2, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "RUM Samples", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[rumWebVitals]}}", - "name": "rumWebVitals", - "pluginConfigId": "{{configId}}", - "group": { - "by": [], - "aggregate": [ - { - "type": "sum", - "names": [ - "count" - ] - } - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-scalar", - "config": { - "data-stream-scalar": { - "value": "count_sum", - "comparisonColumn": "none", - "label": "RUM Samples" - } - } - } - } - }, - { - "i": "0f48a7c9-fcf3-416a-b2f0-d6c2e5cabcc1", - "x": 0, - "y": 36, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Core Web Vitals Trend", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[rumWebVitals]}}", - "name": "rumWebVitals", - "pluginConfigId": "{{configId}}", - "group": { - "by": [ - [ - "dimensions.date", - "byDay" - ] - ], - "aggregate": [ - { - "type": "mean", - "names": [ - "largestContentfulPaintP75" - ] - }, - { - "type": "mean", - "names": [ - "interactionToNextPaintP75" - ] - } - ] - }, - "sort": { - "by": [ - [ - "dimensions.date_byDay", - "asc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "dimensions.date_byDay", - "yAxisColumn": [ - "largestContentfulPaintP75_mean", - "interactionToNextPaintP75_mean" - ], - "seriesColumn": "none", - "showLegend": true, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "1448aa66-c33d-42c8-b310-aab9100ef8a2", - "x": 2, - "y": 36, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Cumulative Layout Shift Trend", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[rumWebVitals]}}", - "name": "rumWebVitals", - "pluginConfigId": "{{configId}}", - "group": { - "by": [ - [ - "dimensions.date", - "byDay" - ] - ], - "aggregate": [ - { - "type": "mean", - "names": [ - "cumulativeLayoutShiftP75" - ] - } - ] - }, - "sort": { - "by": [ - [ - "dimensions.date_byDay", - "asc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "dimensions.date_byDay", - "yAxisColumn": [ - "cumulativeLayoutShiftP75_mean" - ], - "seriesColumn": "none", - "showLegend": false, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "3fa5456b-67bc-4f54-b2f7-9f20cad1aa50", - "x": 0, - "y": 39, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Page Views by Country", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[rumPageLoads]}}", - "name": "rumPageLoads", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "countryName" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "pageViews" - ] - } - ] - }, - "sort": { - "by": [ - [ - "pageViews_sum", - "desc" - ] - ], - "top": 10 - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-bar-chart", - "config": { - "data-stream-bar-chart": { - "xAxisData": "breakdown_uniqueValues", - "yAxisData": [ - "pageViews_sum" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "vertical", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } - } - } - } - } - }, - { - "i": "b46fbd5f-b49c-40e6-9780-39fd9d287f6c", - "x": 2, - "y": 39, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Page Views by Device Type", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[rumPageLoads]}}", - "name": "rumPageLoads", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "deviceType" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "pageViews" - ] - } - ] - }, - "sort": { - "by": [ - [ - "pageViews_sum", - "desc" - ] - ], - "top": 10 - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-donut-chart", - "config": { - "data-stream-donut-chart": { - "valueColumn": "pageViews_sum", - "labelColumn": "breakdown_uniqueValues", - "hideCenterValue": false, - "showValuesAsPercentage": false, - "legendPosition": "auto", - "legendMode": "table" - } - } - } - } - }, - { - "i": "736448a6-7b52-440a-b866-f2f4b23ab048", - "x": 0, - "y": 42, - "w": 4, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Page Views and Visits", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[rumPageLoads]}}", - "name": "rumPageLoads", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "countryName" - }, - "group": { - "by": [ - [ - "date", - "byDay" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "pageViews" - ] - }, - { - "type": "sum", - "names": [ - "visits" - ] - } - ] - }, - "sort": { - "by": [ - [ - "date_byDay", - "asc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "date_byDay", - "yAxisColumn": [ - "pageViews_sum", - "visits_sum" - ], - "seriesColumn": "none", - "showLegend": true, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "bba8874b-de16-4088-ba86-f7a3f1242e6e", - "x": 0, - "y": 45, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "DNS Queries by Type", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneDnsAnalytics]}}", - "name": "zoneDnsAnalytics", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "queryType" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "queryCount" - ] - } - ] - }, - "sort": { - "by": [ - [ - "queryCount_sum", - "desc" - ] - ], - "top": 10 - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-bar-chart", - "config": { - "data-stream-bar-chart": { - "xAxisData": "breakdown_uniqueValues", - "yAxisData": [ - "queryCount_sum" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "vertical", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } - } - } - } - } - }, - { - "i": "c8c8b28e-1fed-4543-87d6-821ef74a884b", - "x": 2, - "y": 45, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "DNS Response Codes", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneDnsAnalytics]}}", - "name": "zoneDnsAnalytics", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "responseCode" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "queryCount" - ] - } - ] - }, - "sort": { - "by": [ - [ - "queryCount_sum", - "desc" - ] - ], - "top": 10 - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-donut-chart", - "config": { - "data-stream-donut-chart": { - "valueColumn": "queryCount_sum", - "labelColumn": "breakdown_uniqueValues", - "hideCenterValue": false, - "showValuesAsPercentage": false, - "legendPosition": "auto", - "legendMode": "table" - } - } - } - } - }, - { - "i": "bb2d2cdd-d041-435a-b77f-47ef0f8190b8", - "x": 0, - "y": 48, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "DNS Queries Over Time", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneDnsAnalytics]}}", - "name": "zoneDnsAnalytics", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "queryType" - }, - "group": { - "by": [ - [ - "date", - "byDay" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "queryCount" - ] - } - ] - }, - "sort": { - "by": [ - [ - "date_byDay", - "asc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "date_byDay", - "yAxisColumn": [ - "queryCount_sum" - ], - "seriesColumn": "none", - "showLegend": false, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "78551a25-ceca-4256-9111-1e195d3afa3b", - "x": 2, - "y": 48, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "DNS Response Time", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneDnsAnalytics]}}", - "name": "zoneDnsAnalytics", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "queryType" - }, - "group": { - "by": [ - [ - "date", - "byDay" - ] - ], - "aggregate": [ - { - "type": "mean", - "names": [ - "avgResponseTimeMs" - ] - } - ] - }, - "sort": { - "by": [ - [ - "date_byDay", - "asc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "date_byDay", - "yAxisColumn": [ - "avgResponseTimeMs_mean" - ], - "seriesColumn": "none", - "showLegend": false, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "5a35c781-2682-4880-bff7-77c61d52ae5f", - "x": 0, - "y": 51, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Email Routing Messages by Action", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[emailRouting]}}", - "name": "emailRouting", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "action" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "messageCount" - ] - } - ] - }, - "sort": { - "by": [ - [ - "messageCount_sum", - "desc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-donut-chart", - "config": { - "data-stream-donut-chart": { - "valueColumn": "messageCount_sum", - "labelColumn": "breakdown_uniqueValues", - "hideCenterValue": false, - "showValuesAsPercentage": false, - "legendPosition": "auto", - "legendMode": "table" - } - } - } - } - }, - { - "i": "e7ec1705-838a-4d37-918b-496b4da2e138", - "x": 2, - "y": 51, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Email Routing Messages Over Time", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[emailRouting]}}", - "name": "emailRouting", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "status" - }, - "group": { - "by": [ - [ - "date", - "byDay" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "messageCount" - ] - } - ] - }, - "sort": { - "by": [ - [ - "date_byDay", - "asc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "date_byDay", - "yAxisColumn": [ - "messageCount_sum" - ], - "seriesColumn": "none", - "showLegend": false, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "404f3e25-56a7-4f0d-b112-e9c12846d0bb", - "x": 0, - "y": 54, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "DMARC Messages by Disposition", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[dmarcReports]}}", - "name": "dmarcReports", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "disposition" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "messageCount" - ] - } - ] - }, - "sort": { - "by": [ - [ - "messageCount_sum", - "desc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-donut-chart", - "config": { - "data-stream-donut-chart": { - "valueColumn": "messageCount_sum", - "labelColumn": "breakdown_uniqueValues", - "hideCenterValue": false, - "showValuesAsPercentage": false, - "legendPosition": "auto", - "legendMode": "table" - } - } - } - } - }, - { - "i": "f741cb88-09ec-49d5-afac-2e55358ec1c9", - "x": 2, - "y": 54, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Top DMARC Sending Organizations", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[dmarcReports]}}", - "name": "dmarcReports", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "sourceOrgName" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "messageCount" - ] - } - ] - }, - "sort": { - "by": [ - [ - "messageCount_sum", - "desc" - ] - ], - "top": 10 - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-bar-chart", - "config": { - "data-stream-bar-chart": { - "xAxisData": "breakdown_uniqueValues", - "yAxisData": [ - "messageCount_sum" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "vertical", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } - } - } - } - } - }, - { - "i": "d2d06e16-5181-4c42-9faf-f5eb6986072f", - "x": 0, - "y": 57, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Cache Reserve Operations by Type", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[cacheReserveOperations]}}", - "name": "cacheReserveOperations", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "operationClass" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "operationCount" - ] - } - ] - }, - "sort": { - "by": [ - [ - "operationCount_sum", - "desc" - ] - ] - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-donut-chart", - "config": { - "data-stream-donut-chart": { - "valueColumn": "operationCount_sum", - "labelColumn": "breakdown_uniqueValues", - "hideCenterValue": false, - "showValuesAsPercentage": false, - "legendPosition": "auto", - "legendMode": "table" - } - } - } - } - }, - { - "i": "2072f98c-365b-4001-9594-eed5b5612479", - "x": 2, - "y": 57, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Cache Reserve Storage", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[cacheReserveStorage]}}", - "name": "cacheReserveStorage", - "pluginConfigId": "{{configId}}", - "group": { - "by": [ - [ - "dimensions.datetime", - "byHour" - ] - ], - "aggregate": [ - { - "type": "max", - "names": [ - "max.storedBytes" - ] - } - ] - }, - "sort": { - "by": [ - [ - "dimensions.datetime_byHour", - "asc" - ] - ] - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "dimensions.datetime_byHour", - "yAxisColumn": [ - "max.storedBytes_max" - ], - "seriesColumn": "none", - "showLegend": false, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "d1d83606-df02-4ee0-88ad-4b88401340ad", - "x": 0, - "y": 60, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Health Check Events by Status", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneHealthCheckEvents]}}", - "name": "zoneHealthCheckEvents", - "pluginConfigId": "{{configId}}", - "group": { - "by": [ - [ - "dimensions.healthStatus", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "count" - ] - } - ] - }, - "sort": { - "by": [ - [ - "count_sum", - "desc" - ] - ] - } - }, - "timeframe": "last24hours", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-donut-chart", - "config": { - "data-stream-donut-chart": { - "valueColumn": "count_sum", - "labelColumn": "dimensions.healthStatus_uniqueValues", - "hideCenterValue": false, - "showValuesAsPercentage": false, - "legendPosition": "auto", - "legendMode": "table" - } - } - } - } - }, - { - "i": "18a14576-aa42-440d-8f32-28024ebb0003", - "x": 2, - "y": 60, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Health Check Round Trip Time", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneHealthCheckEvents]}}", - "name": "zoneHealthCheckEvents", - "pluginConfigId": "{{configId}}", - "group": { - "by": [ - [ - "dimensions.datetime", - "byHour" - ] - ], - "aggregate": [ - { - "type": "mean", - "names": [ - "avg.rttMs" - ] - } - ] - }, - "sort": { - "by": [ - [ - "dimensions.datetime_byHour", - "asc" - ] - ] - } - }, - "timeframe": "last24hours", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "dimensions.datetime_byHour", - "yAxisColumn": [ - "avg.rttMs_mean" - ], - "seriesColumn": "none", - "showLegend": false, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - } - } - }, - { - "i": "0b37e21b-6c6a-4442-8a58-507f77fb6451", - "x": 0, - "y": 63, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Network Error Logging by Error Type", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zoneNelReports]}}", - "name": "zoneNelReports", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "type" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "events" - ] - } - ] - }, - "sort": { - "by": [ - [ - "events_sum", - "desc" - ] - ], - "top": 10 - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-bar-chart", - "config": { - "data-stream-bar-chart": { - "xAxisData": "breakdown_uniqueValues", - "yAxisData": [ - "events_sum" - ], - "xAxisGroup": "none", - "xAxisLabel": "", - "yAxisLabel": "", - "showXAxisLabel": false, - "showYAxisLabel": false, - "showLegend": false, - "legendPosition": "bottom", - "showGrid": true, - "horizontalLayout": "vertical", - "displayMode": "actual", - "showTotals": false, - "showValue": false, - "grouping": false, - "range": { - "type": "auto" - } - } - } - } - } - }, - { - "i": "60c857c2-28a9-47cf-b0aa-85676a291c9f", - "x": 2, - "y": 63, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Page Shield Events by Resource Type", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[zonePageShield]}}", - "name": "zonePageShield", - "pluginConfigId": "{{configId}}", - "dataSourceConfig": { - "breakdown": "resourceType" - }, - "group": { - "by": [ - [ - "breakdown", - "uniqueValues" - ] - ], - "aggregate": [ - { - "type": "sum", - "names": [ - "events" - ] - } - ] - }, - "sort": { - "by": [ - [ - "events_sum", - "desc" - ] - ] - } - }, - "timeframe": "last7days", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-donut-chart", - "config": { - "data-stream-donut-chart": { - "valueColumn": "events_sum", - "labelColumn": "breakdown_uniqueValues", - "hideCenterValue": false, - "showValuesAsPercentage": false, - "legendPosition": "auto", - "legendMode": "table" - } - } - } - } - }, - { - "i": "7777d765-1ec1-470d-8e6a-6c70e15637a9", - "x": 0, - "y": 66, - "w": 4, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Page Load Timing (P75)", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "{{dataStreams.[rumPageLoadTiming]}}", - "name": "rumPageLoadTiming", - "pluginConfigId": "{{configId}}", - "sort": { - "by": [ - [ - "dimensions.date", - "asc" - ] - ] - } - }, - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}", - "variable": "{{variables.[Cloudflare Zone]}}" - }, - "variables": [ - "{{variables.[Cloudflare Zone]}}" - ], - "visualisation": { - "type": "data-stream-line-graph", - "config": { - "data-stream-line-graph": { - "xAxisColumn": "dimensions.date", - "yAxisColumn": [ - "dnsTime", - "connectionTime", - "requestTime", - "responseTime", - "firstContentfulPaint", - "pageLoadTime" - ], - "seriesColumn": "none", - "showLegend": true, - "legendPosition": "bottom", - "showYAxisLabel": false, - "showTrendLine": false - } - } - }, - "timeframe": "last7days" - } - } - ] - } -} diff --git a/plugins/Cloudflare/v2/defaultContent/Traffic/manifest.json b/plugins/Cloudflare/v2/defaultContent/Traffic/manifest.json deleted file mode 100644 index de31d756..00000000 --- a/plugins/Cloudflare/v2/defaultContent/Traffic/manifest.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "items": [ - { - "name": "loadBalancerPool", - "type": "dashboard" - } - ] -} diff --git a/plugins/Cloudflare/v2/defaultContent/Zero Trust/tunnel.dash.json b/plugins/Cloudflare/v2/defaultContent/Zero Trust/tunnel.dash.json index c0ce8dfa..cacf907e 100644 --- a/plugins/Cloudflare/v2/defaultContent/Zero Trust/tunnel.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Zero Trust/tunnel.dash.json @@ -119,7 +119,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "Data Centres", + "title": "Data Centers", "description": "", "activePluginConfigIds": [ "{{configId}}" @@ -155,7 +155,7 @@ "data-stream-scalar": { "value": "colo_name_distinctCount", "comparisonColumn": "none", - "label": "Data Centres" + "label": "Data Centers" } } } @@ -172,7 +172,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "Connections by Data Centre", + "title": "Connections by Data Center", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Traffic/loadBalancerPool.dash.json b/plugins/Cloudflare/v2/defaultContent/Zones/loadBalancerPool.dash.json similarity index 99% rename from plugins/Cloudflare/v2/defaultContent/Traffic/loadBalancerPool.dash.json rename to plugins/Cloudflare/v2/defaultContent/Zones/loadBalancerPool.dash.json index fee2e185..6a39de34 100644 --- a/plugins/Cloudflare/v2/defaultContent/Traffic/loadBalancerPool.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/Zones/loadBalancerPool.dash.json @@ -245,7 +245,7 @@ "z": 0, "config": { "_type": "tile/data-stream", - "title": "Checks by Data Centre", + "title": "Checks by Data Center", "description": "", "activePluginConfigIds": [ "{{configId}}" diff --git a/plugins/Cloudflare/v2/defaultContent/Zones/manifest.json b/plugins/Cloudflare/v2/defaultContent/Zones/manifest.json new file mode 100644 index 00000000..ded2fbf2 --- /dev/null +++ b/plugins/Cloudflare/v2/defaultContent/Zones/manifest.json @@ -0,0 +1,28 @@ +{ + "items": [ + { + "name": "zone", + "type": "dashboard" + }, + { + "name": "zoneTraffic", + "type": "dashboard" + }, + { + "name": "zoneWebPerformance", + "type": "dashboard" + }, + { + "name": "zoneSecurity", + "type": "dashboard" + }, + { + "name": "zoneDnsEmail", + "type": "dashboard" + }, + { + "name": "loadBalancerPool", + "type": "dashboard" + } + ] +} diff --git a/plugins/Cloudflare/v2/defaultContent/Zones/zone.dash.json b/plugins/Cloudflare/v2/defaultContent/Zones/zone.dash.json new file mode 100644 index 00000000..e991ea9b --- /dev/null +++ b/plugins/Cloudflare/v2/defaultContent/Zones/zone.dash.json @@ -0,0 +1,763 @@ +{ + "name": "Zone", + "schemaVersion": "1.5", + "timeframe": "last24hours", + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "dbbd193c-5a10-4b49-8a2b-f33b1fe54efe", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Requests", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTraffic]}}", + "name": "zoneTraffic", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.requests" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.requests_sum", + "comparisonColumn": "none", + "label": "Requests" + } + } + } + } + }, + { + "i": "359ed863-1182-4dea-8299-3ed8a3b75b22", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Unique Visitors", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTraffic]}}", + "name": "zoneTraffic", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "uniq.uniques" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "uniq.uniques_sum", + "comparisonColumn": "none", + "label": "Unique Visitors" + } + } + } + } + }, + { + "i": "1cac5d62-0609-4166-9ead-ba20f448f830", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Bandwidth", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTraffic]}}", + "name": "zoneTraffic", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.bytes" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.bytes_sum", + "comparisonColumn": "none", + "label": "Bandwidth" + } + } + } + } + }, + { + "i": "2d0590e9-4c6b-460d-8919-c2658524e750", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Threats", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTraffic]}}", + "name": "zoneTraffic", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "sum.threats" + ] + } + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "sum.threats_sum", + "comparisonColumn": "none", + "label": "Threats" + } + } + } + } + }, + { + "i": "086887f6-cec2-47b8-bf3e-1f2b8d8f5eb5", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Zone Status", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneStatus]}}", + "name": "zoneStatus", + "pluginConfigId": "{{configId}}" + }, + "timeframe": "none", + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "state", + "sublabel": "plan.name", + "linkColumn": "name", + "columns": 1 + } + } + }, + "monitor": { + "_type": "simple", + "tileRollsUp": true, + "monitorType": "state", + "column": "state", + "aggregation": "top", + "condition": { + "columns": [ + "state" + ] + }, + "frequency": 15 + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ] + } + }, + { + "i": "a73efcb0-71d7-4148-91c5-56edd3518568", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Zone Details", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties" + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": true, + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type" + ] + } + } + } + } + }, + { + "i": "4b177d07-939f-4a35-9b5b-d47d7cad13c8", + "x": 0, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Requests", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTraffic]}}", + "name": "zoneTraffic", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime", + "yAxisColumn": [ + "sum.requests", + "sum.cachedRequests" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "2b949c2a-6bd1-480b-8b02-78ae669d7be4", + "x": 2, + "y": 5, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Bandwidth", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTraffic]}}", + "name": "zoneTraffic", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime", + "yAxisColumn": [ + "sum.bytes", + "sum.cachedBytes" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "2ce8c81d-92e5-4e30-b1fb-95a45e1c567d", + "x": 0, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Cache Hit Ratio", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTraffic]}}", + "name": "zoneTraffic", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime", + "yAxisColumn": [ + "cacheHitRatio" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "6084f30d-d547-4fdf-8712-6ac71b5fb03a", + "x": 2, + "y": 8, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "SSL Certificates", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneCertificates]}}", + "name": "zoneCertificates", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "daysUntilExpiry", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "hosts", + "status", + "daysUntilExpiry", + "expiresOn", + "certificateAuthority", + "type" + ], + "hiddenColumns": [ + "id", + "issuer", + "validationMethod" + ] + } + } + } + } + }, + { + "i": "b32501ab-3b1e-47da-bb9c-19fab121891f", + "x": 0, + "y": 11, + "w": 2, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Health Checks", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneHealthChecks]}}", + "name": "zoneHealthChecks", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "name", + "status", + "address", + "type", + "failure_reason", + "suspended" + ], + "hiddenColumns": [ + "id", + "interval", + "timeout", + "consecutive_fails", + "consecutive_successes", + "check_regions", + "created_on", + "modified_on" + ] + } + } + } + } + }, + { + "i": "d1d83606-df02-4ee0-88ad-4b88401340ad", + "x": 2, + "y": 12, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Health Check Events by Status", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneHealthCheckEvents]}}", + "name": "zoneHealthCheckEvents", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.healthStatus", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ] + } + }, + "timeframe": "last24hours", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "count_sum", + "labelColumn": "dimensions.healthStatus_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "18a14576-aa42-440d-8f32-28024ebb0003", + "x": 0, + "y": 15, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Health Check Round Trip Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneHealthCheckEvents]}}", + "name": "zoneHealthCheckEvents", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetime", + "byHour" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "avg.rttMs" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.datetime_byHour", + "asc" + ] + ] + } + }, + "timeframe": "last24hours", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byHour", + "yAxisColumn": [ + "avg.rttMs_mean" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v2/defaultContent/Zones/zoneDnsEmail.dash.json b/plugins/Cloudflare/v2/defaultContent/Zones/zoneDnsEmail.dash.json new file mode 100644 index 00000000..463aa91b --- /dev/null +++ b/plugins/Cloudflare/v2/defaultContent/Zones/zoneDnsEmail.dash.json @@ -0,0 +1,693 @@ +{ + "name": "Zone DNS & Email", + "schemaVersion": "1.5", + "timeframe": "last24hours", + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "bb2d2cdd-d041-435a-b77f-47ef0f8190b8", + "x": 0, + "y": 0, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "DNS Queries Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneDnsAnalytics]}}", + "name": "zoneDnsAnalytics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "queryType" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "queryCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "queryCount_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "78551a25-ceca-4256-9111-1e195d3afa3b", + "x": 2, + "y": 0, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "DNS Response Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneDnsAnalytics]}}", + "name": "zoneDnsAnalytics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "queryType" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "avgResponseTimeMs" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "avgResponseTimeMs_mean" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "bba8874b-de16-4088-ba86-f7a3f1242e6e", + "x": 0, + "y": 3, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "DNS Queries by Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneDnsAnalytics]}}", + "name": "zoneDnsAnalytics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "queryType" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "queryCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "queryCount_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "queryCount_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "c8c8b28e-1fed-4543-87d6-821ef74a884b", + "x": 2, + "y": 3, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "DNS Response Codes", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneDnsAnalytics]}}", + "name": "zoneDnsAnalytics", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "responseCode" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "queryCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "queryCount_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "queryCount_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "2a5caeac-bbae-4322-934c-4a58f34091f0", + "x": 0, + "y": 6, + "w": 4, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "DNS Records", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneDnsRecords]}}", + "name": "zoneDnsRecords", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "name", + "type", + "content", + "proxied", + "ttl", + "comment" + ], + "hiddenColumns": [ + "id", + "tags", + "created_on", + "modified_on" + ] + } + } + } + } + }, + { + "i": "e7ec1705-838a-4d37-918b-496b4da2e138", + "x": 0, + "y": 10, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Email Routing Messages Over Time", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[emailRouting]}}", + "name": "emailRouting", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "status" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "messageCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "messageCount_sum" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "5a35c781-2682-4880-bff7-77c61d52ae5f", + "x": 2, + "y": 10, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Email Routing Messages by Action", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[emailRouting]}}", + "name": "emailRouting", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "action" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "messageCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "messageCount_sum", + "desc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "messageCount_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "404f3e25-56a7-4f0d-b112-e9c12846d0bb", + "x": 0, + "y": 13, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "DMARC Messages by Disposition", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[dmarcReports]}}", + "name": "dmarcReports", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "disposition" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "messageCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "messageCount_sum", + "desc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "messageCount_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "f741cb88-09ec-49d5-afac-2e55358ec1c9", + "x": 2, + "y": 13, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Top DMARC Sending Organizations", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[dmarcReports]}}", + "name": "dmarcReports", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "sourceOrgName" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "messageCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "messageCount_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "messageCount_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v2/defaultContent/Zones/zoneSecurity.dash.json b/plugins/Cloudflare/v2/defaultContent/Zones/zoneSecurity.dash.json new file mode 100644 index 00000000..f50b4cb6 --- /dev/null +++ b/plugins/Cloudflare/v2/defaultContent/Zones/zoneSecurity.dash.json @@ -0,0 +1,523 @@ +{ + "name": "Zone Security", + "schemaVersion": "1.5", + "timeframe": "last24hours", + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "414ccb22-cce5-4121-ba54-ba0c4ae80aa8", + "x": 0, + "y": 0, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Firewall Events (Last 30 Days)", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneFirewallEventVolume]}}", + "name": "zoneFirewallEventVolume", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "datetime", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "timeframe": "last30days", + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "datetime", + "yAxisColumn": [ + "events" + ], + "seriesColumn": "zoneName", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "36980a5b-9966-4da8-b4ae-03a64c40c648", + "x": 0, + "y": 3, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Firewall Actions", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneFirewallEvents]}}", + "name": "zoneFirewallEvents", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "source" + }, + "group": { + "by": [ + [ + "action", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "events" + ] + } + ] + }, + "sort": { + "by": [ + [ + "events_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "events_sum", + "labelColumn": "action_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "f70d4a4d-aa25-436e-bc2d-f57913923742", + "x": 2, + "y": 3, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Firewall Events by Service", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneFirewallEvents]}}", + "name": "zoneFirewallEvents", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "source" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "events" + ] + } + ] + }, + "sort": { + "by": [ + [ + "events_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "events_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "b5b428c0-6e8b-4b20-8637-826523d8875e", + "x": 0, + "y": 6, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Firewall Events by Rule", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneFirewallEvents]}}", + "name": "zoneFirewallEvents", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "ruleId" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "events" + ] + } + ] + }, + "sort": { + "by": [ + [ + "events_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "events_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "ab07298c-beb2-45ad-ab55-973b5ee13c9e", + "x": 2, + "y": 6, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Firewall Events by Country", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneFirewallEvents]}}", + "name": "zoneFirewallEvents", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "clientCountryName" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "events" + ] + } + ] + }, + "sort": { + "by": [ + [ + "events_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "events_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "bb0a1d4a-34c2-4cf2-be6d-196aa666ecd3", + "x": 0, + "y": 9, + "w": 4, + "h": 5, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Firewall Event Log", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneFirewallEventLog]}}", + "name": "zoneFirewallEventLog", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "datetime", + "desc" + ] + ] + } + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "datetime", + "actionState", + "action", + "source", + "description", + "clientIP", + "clientCountryName", + "clientRequestHTTPHost", + "clientRequestPath", + "rayName" + ], + "hiddenColumns": [ + "ruleId", + "clientASNDescription", + "clientRequestHTTPMethodName", + "userAgent", + "edgeResponseStatus" + ] + } + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ] + } + }, + { + "i": "60c857c2-28a9-47cf-b0aa-85676a291c9f", + "x": 0, + "y": 14, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Page Shield Events by Resource Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zonePageShield]}}", + "name": "zonePageShield", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "resourceType" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "events" + ] + } + ] + }, + "sort": { + "by": [ + [ + "events_sum", + "desc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "events_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v2/defaultContent/Zones/zoneTraffic.dash.json b/plugins/Cloudflare/v2/defaultContent/Zones/zoneTraffic.dash.json new file mode 100644 index 00000000..9aa87338 --- /dev/null +++ b/plugins/Cloudflare/v2/defaultContent/Zones/zoneTraffic.dash.json @@ -0,0 +1,756 @@ +{ + "name": "Zone Traffic", + "schemaVersion": "1.5", + "timeframe": "last24hours", + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "8a7c2e43-e5a1-4fb8-a862-3bf8ec9f364d", + "x": 0, + "y": 0, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Traffic by Country", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTrafficBreakdown]}}", + "name": "zoneTrafficBreakdown", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "clientCountryName" + }, + "sort": { + "by": [ + [ + "requests", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown", + "yAxisData": [ + "requests" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "babb40cf-e759-4887-8474-8649bfc1a846", + "x": 2, + "y": 0, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Traffic by Status Code", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTrafficBreakdown]}}", + "name": "zoneTrafficBreakdown", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "edgeResponseStatus" + }, + "sort": { + "by": [ + [ + "requests", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "requests", + "labelColumn": "breakdown", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "5c613d78-1252-432a-b699-9064fe5625bc", + "x": 0, + "y": 3, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Cache Status", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTrafficBreakdown]}}", + "name": "zoneTrafficBreakdown", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "cacheStatus" + }, + "sort": { + "by": [ + [ + "requests", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "requests", + "labelColumn": "breakdown", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "fb685bc2-f0f1-4d13-b965-4852d361d7bc", + "x": 2, + "y": 3, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Traffic by Device Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTrafficBreakdown]}}", + "name": "zoneTrafficBreakdown", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "clientDeviceType" + }, + "sort": { + "by": [ + [ + "requests", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "requests", + "labelColumn": "breakdown", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "710d825b-71be-494f-bc23-867b6435d5c3", + "x": 0, + "y": 6, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Traffic by SSL Protocol", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTrafficBreakdown]}}", + "name": "zoneTrafficBreakdown", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "clientSSLProtocol" + }, + "sort": { + "by": [ + [ + "requests", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "requests", + "labelColumn": "breakdown", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "89d0acb0-7a75-4c20-a4be-f671917579e4", + "x": 2, + "y": 6, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Traffic by Request Source", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneTrafficBreakdown]}}", + "name": "zoneTrafficBreakdown", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "requestSource" + }, + "sort": { + "by": [ + [ + "requests", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "requests", + "labelColumn": "breakdown", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "4340f0d4-7cb2-495e-a086-4b115ac7eede", + "x": 0, + "y": 9, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Load Balancing by Pool", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneLoadBalancing]}}", + "name": "zoneLoadBalancing", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.selectedPoolName", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "dimensions.selectedPoolName_uniqueValues", + "yAxisData": [ + "count_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "d0c74ae9-3aca-4708-a4a1-373db8a88696", + "x": 2, + "y": 9, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Load Balancing by Origin", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneLoadBalancing]}}", + "name": "zoneLoadBalancing", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.selectedOriginName", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + }, + "sort": { + "by": [ + [ + "count_sum", + "desc" + ] + ], + "top": 10 + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "dimensions.selectedOriginName_uniqueValues", + "yAxisData": [ + "count_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "d2d06e16-5181-4c42-9faf-f5eb6986072f", + "x": 0, + "y": 12, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Cache Reserve Operations by Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[cacheReserveOperations]}}", + "name": "cacheReserveOperations", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "operationClass" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "operationCount" + ] + } + ] + }, + "sort": { + "by": [ + [ + "operationCount_sum", + "desc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "operationCount_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "2072f98c-365b-4001-9594-eed5b5612479", + "x": 2, + "y": 12, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Cache Reserve Storage", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[cacheReserveStorage]}}", + "name": "cacheReserveStorage", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.datetime", + "byHour" + ] + ], + "aggregate": [ + { + "type": "max", + "names": [ + "max.storedBytes" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.datetime_byHour", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.datetime_byHour", + "yAxisColumn": [ + "max.storedBytes_max" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "0b37e21b-6c6a-4442-8a58-507f77fb6451", + "x": 0, + "y": 15, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Network Error Logging by Error Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneNelReports]}}", + "name": "zoneNelReports", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "type" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "events" + ] + } + ] + }, + "sort": { + "by": [ + [ + "events_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "events_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v2/defaultContent/Zones/zoneWebPerformance.dash.json b/plugins/Cloudflare/v2/defaultContent/Zones/zoneWebPerformance.dash.json new file mode 100644 index 00000000..39374958 --- /dev/null +++ b/plugins/Cloudflare/v2/defaultContent/Zones/zoneWebPerformance.dash.json @@ -0,0 +1,681 @@ +{ + "name": "Zone Web Performance", + "schemaVersion": "1.5", + "timeframe": "last24hours", + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "99e46b39-b7fd-4d39-8990-7bfec62f4a92", + "x": 0, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "LCP (P75)", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumWebVitals]}}", + "name": "rumWebVitals", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "mean", + "names": [ + "largestContentfulPaintP75" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "largestContentfulPaintP75_mean", + "comparisonColumn": "none", + "label": "LCP (P75)" + } + } + } + } + }, + { + "i": "5817c6a0-7759-4c3a-93a8-dfce7f44fc97", + "x": 1, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "INP (P75)", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumWebVitals]}}", + "name": "rumWebVitals", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "mean", + "names": [ + "interactionToNextPaintP75" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "interactionToNextPaintP75_mean", + "comparisonColumn": "none", + "label": "INP (P75)" + } + } + } + } + }, + { + "i": "3681fbe9-0fb2-449b-85c3-f66e81c37fe3", + "x": 2, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "CLS (P75)", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumWebVitals]}}", + "name": "rumWebVitals", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "mean", + "names": [ + "cumulativeLayoutShiftP75" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "cumulativeLayoutShiftP75_mean", + "comparisonColumn": "none", + "label": "CLS (P75)" + } + } + } + } + }, + { + "i": "865ade66-66ea-441f-a6d0-27a3d8a7f26d", + "x": 3, + "y": 0, + "w": 1, + "h": 2, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "RUM Samples", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumWebVitals]}}", + "name": "rumWebVitals", + "pluginConfigId": "{{configId}}", + "group": { + "by": [], + "aggregate": [ + { + "type": "sum", + "names": [ + "count" + ] + } + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-scalar", + "config": { + "data-stream-scalar": { + "value": "count_sum", + "comparisonColumn": "none", + "label": "RUM Samples" + } + } + } + } + }, + { + "i": "0f48a7c9-fcf3-416a-b2f0-d6c2e5cabcc1", + "x": 0, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Core Web Vitals Trend", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumWebVitals]}}", + "name": "rumWebVitals", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "largestContentfulPaintP75" + ] + }, + { + "type": "mean", + "names": [ + "interactionToNextPaintP75" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "largestContentfulPaintP75_mean", + "interactionToNextPaintP75_mean" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "1448aa66-c33d-42c8-b310-aab9100ef8a2", + "x": 2, + "y": 2, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Cumulative Layout Shift Trend", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumWebVitals]}}", + "name": "rumWebVitals", + "pluginConfigId": "{{configId}}", + "group": { + "by": [ + [ + "dimensions.date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "mean", + "names": [ + "cumulativeLayoutShiftP75" + ] + } + ] + }, + "sort": { + "by": [ + [ + "dimensions.date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date_byDay", + "yAxisColumn": [ + "cumulativeLayoutShiftP75_mean" + ], + "seriesColumn": "none", + "showLegend": false, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "736448a6-7b52-440a-b866-f2f4b23ab048", + "x": 0, + "y": 5, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Page Views and Visits", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumPageLoads]}}", + "name": "rumPageLoads", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "countryName" + }, + "group": { + "by": [ + [ + "date", + "byDay" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "pageViews" + ] + }, + { + "type": "sum", + "names": [ + "visits" + ] + } + ] + }, + "sort": { + "by": [ + [ + "date_byDay", + "asc" + ] + ] + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "date_byDay", + "yAxisColumn": [ + "pageViews_sum", + "visits_sum" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + } + } + }, + { + "i": "3fa5456b-67bc-4f54-b2f7-9f20cad1aa50", + "x": 0, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Page Views by Country", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumPageLoads]}}", + "name": "rumPageLoads", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "countryName" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "pageViews" + ] + } + ] + }, + "sort": { + "by": [ + [ + "pageViews_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-bar-chart", + "config": { + "data-stream-bar-chart": { + "xAxisData": "breakdown_uniqueValues", + "yAxisData": [ + "pageViews_sum" + ], + "xAxisGroup": "none", + "xAxisLabel": "", + "yAxisLabel": "", + "showXAxisLabel": false, + "showYAxisLabel": false, + "showLegend": false, + "legendPosition": "bottom", + "showGrid": true, + "horizontalLayout": "vertical", + "displayMode": "actual", + "showTotals": false, + "showValue": false, + "grouping": false, + "range": { + "type": "auto" + } + } + } + } + } + }, + { + "i": "b46fbd5f-b49c-40e6-9780-39fd9d287f6c", + "x": 2, + "y": 8, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Page Views by Device Type", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumPageLoads]}}", + "name": "rumPageLoads", + "pluginConfigId": "{{configId}}", + "dataSourceConfig": { + "breakdown": "deviceType" + }, + "group": { + "by": [ + [ + "breakdown", + "uniqueValues" + ] + ], + "aggregate": [ + { + "type": "sum", + "names": [ + "pageViews" + ] + } + ] + }, + "sort": { + "by": [ + [ + "pageViews_sum", + "desc" + ] + ], + "top": 10 + } + }, + "timeframe": "last7days", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-donut-chart", + "config": { + "data-stream-donut-chart": { + "valueColumn": "pageViews_sum", + "labelColumn": "breakdown_uniqueValues", + "hideCenterValue": false, + "showValuesAsPercentage": false, + "legendPosition": "auto", + "legendMode": "table" + } + } + } + } + }, + { + "i": "7777d765-1ec1-470d-8e6a-6c70e15637a9", + "x": 0, + "y": 11, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Page Load Timing (P75)", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[rumPageLoadTiming]}}", + "name": "rumPageLoadTiming", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "dimensions.date", + "asc" + ] + ] + } + }, + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}", + "variable": "{{variables.[Cloudflare Zone]}}" + }, + "variables": [ + "{{variables.[Cloudflare Zone]}}" + ], + "visualisation": { + "type": "data-stream-line-graph", + "config": { + "data-stream-line-graph": { + "xAxisColumn": "dimensions.date", + "yAxisColumn": [ + "dnsTime", + "connectionTime", + "requestTime", + "responseTime", + "firstContentfulPaint", + "pageLoadTime" + ], + "seriesColumn": "none", + "showLegend": true, + "legendPosition": "bottom", + "showYAxisLabel": false, + "showTrendLine": false + } + } + }, + "timeframe": "last7days" + } + } + ] + } +} diff --git a/plugins/Cloudflare/v2/defaultContent/inventory.dash.json b/plugins/Cloudflare/v2/defaultContent/inventory.dash.json new file mode 100644 index 00000000..b54bc63f --- /dev/null +++ b/plugins/Cloudflare/v2/defaultContent/inventory.dash.json @@ -0,0 +1,1152 @@ +{ + "name": "Inventory", + "schemaVersion": "1.5", + "timeframe": "none", + "variables": [], + "dashboard": { + "_type": "layout/grid", + "columns": 4, + "version": 1, + "contents": [ + { + "i": "2bbc6141-d374-41c7-93b1-3b3f7677c193", + "x": 0, + "y": 0, + "w": 4, + "h": 4, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Zone Inventory", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "name", + "status", + "planName", + "accountName", + "zoneType", + "developmentModeActive", + "activatedOn" + ], + "hiddenColumns": [ + "id", + "label", + "link", + "links", + "sourceId", + "sourceName", + "type", + "sourceType", + "accountId", + "paused", + "createdOn", + "nameServers" + ], + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "5be40674-431e-465f-94fc-3b658438dc77", + "x": 0, + "y": 4, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Workers", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Workers]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "usageModel", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "f51e9fdc-9a9e-4272-b24d-9d5d11eac793", + "x": 2, + "y": 4, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Pages Projects", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Pages Projects]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "latestDeploymentStatus", + "sublabel": "productionBranch", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "f2587bfd-deef-45ac-9501-1d66bf9c7734", + "x": 0, + "y": 7, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Tunnels", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Tunnels]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "status", + "sublabel": "tunnelType", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "af6eee0c-cfbf-43e1-a51c-53dca0e9a356", + "x": 2, + "y": 7, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Load Balancer Pools", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Load Balancer Pools]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "9beee6df-b954-4c3f-9c99-dd09a66a3f6a", + "x": 0, + "y": 10, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "R2 Buckets", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare R2 Buckets]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "location", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "c6e175b9-164a-4b14-a4a2-22312083c04f", + "x": 2, + "y": 10, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "D1 Databases", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare D1 Databases]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "62ced3d6-e538-4573-af2c-24365a1d7b52", + "x": 0, + "y": 13, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "KV Namespaces", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare KV Namespaces]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "4a7ce999-9bb4-48f9-890d-6d6dcb4d5e49", + "x": 2, + "y": 13, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Queues", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Queues]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "0db6f61a-dc9f-499c-bd92-b863f2cc9eed", + "x": 0, + "y": 16, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Access Applications", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Access Applications]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "domain", + "linkColumn": "link", + "columns": 4, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "2e3d6f85-4a2c-4429-b1cc-f1b1a7750964", + "x": 0, + "y": 19, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Durable Object Namespaces", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "scriptName", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "f8197c33-da9e-4c1f-91eb-03271dec641f", + "x": 2, + "y": 19, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Vectorize Indexes", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Vectorize Indexes]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "metric", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "6f46fa83-d107-4c9e-a103-bb10026a3f91", + "x": 0, + "y": 22, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Hyperdrive Configs", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Hyperdrive Configs]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "database", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "7c07b110-f283-4502-a0fc-9d8790815b9c", + "x": 2, + "y": 22, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Worker Routes", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[workerRoutes]}}", + "name": "workerRoutes", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "pattern", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-table", + "config": { + "data-stream-table": { + "transpose": false, + "columnOrder": [ + "pattern", + "scriptName", + "zoneName" + ], + "hiddenColumns": [ + "sourceId", + "accountId", + "zoneId", + "workerSourceId" + ] + } + } + } + } + }, + { + "i": "2115654f-a854-4c27-8231-e3d8dc3cd77c", + "x": 0, + "y": 25, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Worker Bindings", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Worker Bindings]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "bindingType", + "linkColumn": "link", + "columns": 4, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "24cf5eb9-6bad-433f-a748-637d668a707b", + "x": 0, + "y": 28, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Stream Videos", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Stream Videos]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "statusState", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "c4afc6e8-d873-439e-b23a-524115490249", + "x": 2, + "y": 28, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Turnstile Widgets", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Turnstile Widgets]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "mode", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "f1c1ad4a-931b-4987-a772-d8367090ef02", + "x": 0, + "y": 31, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "AI Gateways", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare AI Gateways]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "ca16cfd0-c194-409b-94a6-4d4297c9254a", + "x": 2, + "y": 31, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "AutoRAGs", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare AutoRAGs]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "status", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "2dc4925f-e310-48f8-aa1a-8cc5b80e52d4", + "x": 0, + "y": 34, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Container Applications", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Container Applications]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "imageName", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "1ed1f8bb-409a-492e-a0fd-ca4a7682c558", + "x": 2, + "y": 34, + "w": 2, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Pipelines", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Pipelines]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "sublabel": "endpoint", + "linkColumn": "link", + "columns": 2, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + }, + { + "i": "64731322-4823-4187-8d15-cfa52d8f0c58", + "x": 0, + "y": 37, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Realtime Apps", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "datastream-properties", + "name": "properties", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Realtime Apps]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "none", + "linkColumn": "link", + "columns": 4, + "rowLinkColumnName": { + "value": "link", + "label": "Link" + } + } + } + } + } + } + ] + } +} diff --git a/plugins/Cloudflare/v2/defaultContent/manifest.json b/plugins/Cloudflare/v2/defaultContent/manifest.json index 16109b00..3de7431e 100644 --- a/plugins/Cloudflare/v2/defaultContent/manifest.json +++ b/plugins/Cloudflare/v2/defaultContent/manifest.json @@ -5,7 +5,15 @@ "type": "dashboard" }, { - "name": "Core", + "name": "inventory", + "type": "dashboard" + }, + { + "name": "Account", + "type": "folder" + }, + { + "name": "Zones", "type": "folder" }, { @@ -24,10 +32,6 @@ "name": "Zero Trust", "type": "folder" }, - { - "name": "Traffic", - "type": "folder" - }, { "name": "Media", "type": "folder" diff --git a/plugins/Cloudflare/v2/defaultContent/overview.dash.json b/plugins/Cloudflare/v2/defaultContent/overview.dash.json index c659bd74..5d44c65f 100644 --- a/plugins/Cloudflare/v2/defaultContent/overview.dash.json +++ b/plugins/Cloudflare/v2/defaultContent/overview.dash.json @@ -682,7 +682,7 @@ } }, { - "i": "ed93f0f7-9697-4096-b385-03cfcca256e8", + "i": "6b70dcfc-f6fe-4f22-a57c-7fa7fa23be9c", "x": 0, "y": 10, "w": 4, @@ -690,6 +690,67 @@ "moved": false, "static": false, "z": 0, + "config": { + "_type": "tile/data-stream", + "title": "Zone Status", + "description": "", + "activePluginConfigIds": [ + "{{configId}}" + ], + "dataStream": { + "id": "{{dataStreams.[zoneStatus]}}", + "name": "zoneStatus", + "pluginConfigId": "{{configId}}", + "sort": { + "by": [ + [ + "name", + "asc" + ] + ] + } + }, + "timeframe": "none", + "scope": { + "scope": "{{scopes.[Cloudflare Zones]}}", + "workspace": "{{workspaceId}}" + }, + "visualisation": { + "type": "data-stream-blocks", + "config": { + "data-stream-blocks": { + "labelColumn": "name", + "stateColumn": "state", + "sublabel": "plan.name", + "linkColumn": "name", + "columns": 4 + } + } + }, + "monitor": { + "_type": "simple", + "tileRollsUp": true, + "monitorType": "state", + "column": "state", + "aggregation": "top", + "condition": { + "columns": [ + "state" + ] + }, + "frequency": 15 + } + } + }, + { + "i": "ed93f0f7-9697-4096-b385-03cfcca256e8", + "x": 0, + "y": 13, + "w": 4, + "h": 3, + "moved": false, + "static": false, + "z": 0, "config": { "_type": "tile/data-stream", "title": "Requests by Zone", @@ -739,7 +800,7 @@ { "i": "f577bcf2-adb3-4fe5-b017-ecc1afe3c320", "x": 0, - "y": 13, + "y": 16, "w": 2, "h": 3, "moved": false, @@ -822,7 +883,7 @@ { "i": "468ed54a-6c84-4380-907b-8fce6d718637", "x": 2, - "y": 13, + "y": 16, "w": 2, "h": 3, "moved": false, @@ -891,7 +952,7 @@ { "i": "01071810-2460-4d6f-ac37-2d8c6c78ace3", "x": 0, - "y": 16, + "y": 19, "w": 2, "h": 3, "moved": false, @@ -952,7 +1013,7 @@ { "i": "06de4718-8250-4cc0-b864-1d9cc11c1394", "x": 2, - "y": 16, + "y": 19, "w": 2, "h": 3, "moved": false, @@ -1009,1192 +1070,6 @@ } } } - }, - { - "i": "6b70dcfc-f6fe-4f22-a57c-7fa7fa23be9c", - "x": 0, - "y": 19, - "w": 4, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Zones", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "status", - "sublabel": "planName", - "linkColumn": "link", - "columns": 4, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "2bbc6141-d374-41c7-93b1-3b3f7677c193", - "x": 0, - "y": 22, - "w": 4, - "h": 4, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Zone Inventory", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Zones]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-table", - "config": { - "data-stream-table": { - "transpose": false, - "columnOrder": [ - "name", - "status", - "planName", - "accountName", - "zoneType", - "developmentModeActive", - "activatedOn" - ], - "hiddenColumns": [ - "id", - "label", - "link", - "links", - "sourceId", - "sourceName", - "type", - "sourceType", - "accountId", - "paused", - "createdOn", - "nameServers" - ], - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "5be40674-431e-465f-94fc-3b658438dc77", - "x": 0, - "y": 26, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Workers", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Workers]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "sublabel": "usageModel", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "f51e9fdc-9a9e-4272-b24d-9d5d11eac793", - "x": 2, - "y": 26, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Pages Projects", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Pages Projects]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "latestDeploymentStatus", - "sublabel": "productionBranch", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "f2587bfd-deef-45ac-9501-1d66bf9c7734", - "x": 0, - "y": 29, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Tunnels", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Tunnels]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "status", - "sublabel": "tunnelType", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "af6eee0c-cfbf-43e1-a51c-53dca0e9a356", - "x": 2, - "y": 29, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Load Balancer Pools", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Load Balancer Pools]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "9beee6df-b954-4c3f-9c99-dd09a66a3f6a", - "x": 0, - "y": 32, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "R2 Buckets", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare R2 Buckets]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "sublabel": "location", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "c6e175b9-164a-4b14-a4a2-22312083c04f", - "x": 2, - "y": 32, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "D1 Databases", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare D1 Databases]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "62ced3d6-e538-4573-af2c-24365a1d7b52", - "x": 0, - "y": 35, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "KV Namespaces", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare KV Namespaces]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "4a7ce999-9bb4-48f9-890d-6d6dcb4d5e49", - "x": 2, - "y": 35, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Queues", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Queues]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "0db6f61a-dc9f-499c-bd92-b863f2cc9eed", - "x": 0, - "y": 38, - "w": 4, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Access Applications", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Access Applications]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "sublabel": "domain", - "linkColumn": "link", - "columns": 4, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "2e3d6f85-4a2c-4429-b1cc-f1b1a7750964", - "x": 0, - "y": 41, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Durable Object Namespaces", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Durable Object Namespaces]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "sublabel": "scriptName", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "f8197c33-da9e-4c1f-91eb-03271dec641f", - "x": 2, - "y": 41, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Vectorize Indexes", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Vectorize Indexes]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "sublabel": "metric", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "6f46fa83-d107-4c9e-a103-bb10026a3f91", - "x": 0, - "y": 44, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Hyperdrive Configs", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Hyperdrive Configs]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "sublabel": "database", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "7c07b110-f283-4502-a0fc-9d8790815b9c", - "x": 2, - "y": 44, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Worker Routes", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Worker Routes]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "sublabel": "scriptName", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "2115654f-a854-4c27-8231-e3d8dc3cd77c", - "x": 0, - "y": 47, - "w": 4, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Worker Bindings", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Worker Bindings]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "sublabel": "bindingType", - "linkColumn": "link", - "columns": 4, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "24cf5eb9-6bad-433f-a748-637d668a707b", - "x": 0, - "y": 50, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Stream Videos", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Stream Videos]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "sublabel": "statusState", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "c4afc6e8-d873-439e-b23a-524115490249", - "x": 2, - "y": 50, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Turnstile Widgets", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Turnstile Widgets]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "sublabel": "mode", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "f1c1ad4a-931b-4987-a772-d8367090ef02", - "x": 0, - "y": 53, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "AI Gateways", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare AI Gateways]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "ca16cfd0-c194-409b-94a6-4d4297c9254a", - "x": 2, - "y": 53, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "AutoRAGs", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare AutoRAGs]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "sublabel": "status", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "2dc4925f-e310-48f8-aa1a-8cc5b80e52d4", - "x": 0, - "y": 56, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Container Applications", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Container Applications]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "sublabel": "imageName", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "1ed1f8bb-409a-492e-a0fd-ca4a7682c558", - "x": 2, - "y": 56, - "w": 2, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Pipelines", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Pipelines]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "sublabel": "endpoint", - "linkColumn": "link", - "columns": 2, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } - }, - { - "i": "64731322-4823-4187-8d15-cfa52d8f0c58", - "x": 0, - "y": 59, - "w": 4, - "h": 3, - "moved": false, - "static": false, - "z": 0, - "config": { - "_type": "tile/data-stream", - "title": "Realtime Apps", - "description": "", - "activePluginConfigIds": [ - "{{configId}}" - ], - "dataStream": { - "id": "datastream-properties", - "name": "properties", - "sort": { - "by": [ - [ - "name", - "asc" - ] - ] - } - }, - "timeframe": "none", - "scope": { - "scope": "{{scopes.[Cloudflare Realtime Apps]}}", - "workspace": "{{workspaceId}}" - }, - "visualisation": { - "type": "data-stream-blocks", - "config": { - "data-stream-blocks": { - "labelColumn": "name", - "stateColumn": "none", - "linkColumn": "link", - "columns": 4, - "rowLinkColumnName": { - "value": "link", - "label": "Link" - } - } - } - } - } } ] } diff --git a/plugins/Cloudflare/v2/docs/README.md b/plugins/Cloudflare/v2/docs/README.md index ee1f95be..de96c9e8 100644 --- a/plugins/Cloudflare/v2/docs/README.md +++ b/plugins/Cloudflare/v2/docs/README.md @@ -45,13 +45,19 @@ For more detail see Cloudflare's own guide to [creating API tokens](https://deve | ------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | -------- | | **API token** | A Cloudflare API token, sent as `Authorization: Bearer ` on every request to the API. | Cloudflare dashboard → [**My Profile → API Tokens**](https://dash.cloudflare.com/profile/api-tokens) → **Create Custom Token**. | Yes | -On save, the plugin verifies the token against Cloudflare's token-verification endpoint. A failure means the token is invalid, expired or revoked - it does **not** check individual permissions, so a token that saves successfully can still return no data for a product whose permission you left out. +On save, the plugin runs three checks: + +1. **Authenticate** verifies the token against Cloudflare's token-verification endpoint. This check must pass; a failure means the token is invalid, expired or revoked. +2. **Check account access** lists the accounts the token can see, and warns if there are none - usually a missing **Account Settings Read** permission or account resources that do not include the account. +3. **Check zone access** does the same for zones, and warns if there are none - usually a missing **Zone Read** permission or zone resources that do not include the zone. + +The second and third checks warn without blocking the save. None of the checks tests individual product permissions, so a token that saves successfully can still return no data for a product whose permission you left out. ## What this plugin monitors -- **Zone traffic and caching** - requests, bandwidth, cached requests and bytes, page views, unique visitors and cache hit ratio for each zone (hourly for the last two days, daily up to a year) or across every zone in an account, plus breakdowns by country, status code, cache status, host, device type, HTTP protocol and content type. -- **Security** - firewall and WAF events by rule, service, country, host, user agent or path, with the action Cloudflare took, and 30-day event trends on every plan; and SSL certificate inventory with days until expiry. -- **DNS and availability** - every DNS record in a zone with its type, content, TTL and proxy status; standalone health checks; and load balancer request distribution and per-origin pool health. +- **Zone traffic and caching** - requests, bandwidth, cached requests and bytes, page views, unique visitors and cache hit ratio for each zone (hourly for the last two days, daily up to a year) or across every zone in an account, plus breakdowns by country, status code, cache status, host, device type, HTTP protocol, SSL protocol, request source and content type. +- **Security** - firewall and WAF events by rule, service, country, host, user agent or path, with the action Cloudflare took; 30-day event trends and a log of individual events on every plan; and SSL certificate inventory with days until expiry. +- **DNS and availability** - each zone's status as a health state; every DNS record in a zone with its type, content, TTL and proxy status; standalone health checks; and load balancer request distribution and per-origin pool health. - **Web performance** - Core Web Vitals (Largest Contentful Paint, Interaction to Next Paint, Cumulative Layout Shift) and page-load volume and timing (DNS, connection, response, first contentful paint, page load) from Cloudflare Web Analytics, per zone. - **Developer platform** - Worker invocations, errors and CPU-time percentiles, outbound subrequests and response time, cron trigger runs, static asset and Cache API requests, Smart Placement and build minutes; R2 bucket operations, bandwidth and stored size; KV operations, latency and stored keys; D1 query counts, rows touched and database size; Queue message operations and backlog, including delayed messages; Durable Object invocations, active and CPU time, errors, memory and storage; Vectorize query volume; Hyperdrive query volume and connection pool; Workers AI inference by model; and Pages deployment history with branch and commit. - **Dependency mapping** - which Worker binds which KV namespace, R2 bucket, D1 database, queue, Durable Object namespace, Vectorize index or Hyperdrive config, and which zones each Worker serves. @@ -60,14 +66,16 @@ On save, the plugin verifies the token against Cloudflare's token-verification e - **AI platform** - AI Gateway requests, errors, cache and cost by model or provider; AutoRAG query volume; Vectorize; Workers AI inference; and Browser Rendering sessions. - **Email** - Email Routing message flow and DMARC alignment per zone. -The out-of-the-box dashboards open with a **Cloudflare Overview**, with perspectives grouped by Cloudflare product family - Core, Compute, Storage & Databases, AI, Media, Zero Trust and Traffic. Worker Routes and Worker Bindings are indexed and drive the relationship graph but have no perspective of their own. +The out-of-the-box dashboards open with an **Overview** of every account and zone and an **Inventory** of every imported resource. Perspectives are grouped into folders: **Account** (Account, Account Resources, Account Zero Trust and Account Developer Platform), **Zones** (Zone, Zone Traffic, Zone Web Performance, Zone Security, Zone DNS & Email and Load Balancer Pool), Compute, Storage & Databases, AI, Zero Trust and Media. Worker Routes and Worker Bindings are indexed and drive the relationship graph but have no perspective of their own. ## Data streams - **Zone Traffic** - requests, bandwidth, cached traffic, threats, page views and cache hit ratio for a zone, hourly for timeframes up to two days and daily beyond. -- **Zone Traffic Breakdown** - requests, bytes and visits for a zone grouped by a dimension you choose (country, status code, cache status, host, device type, HTTP protocol or content type). +- **Zone Traffic Breakdown** - requests, bytes and visits for a zone grouped by a dimension you choose (country, status code, cache status, host, device type, HTTP protocol, SSL protocol, request source or content type). SSL protocol `none` is unencrypted HTTP; request source separates visitor traffic (`eyeball`) from requests made by Workers. - **Zone Firewall Events** - firewall and WAF event counts for a zone by action, grouped by rule, service, country, host, user agent or path. - **Zone Firewall Event Volume** - firewall and WAF event counts over time for a zone, optionally filtered by action and service, for up to 30 days on every plan. +- **Zone Firewall Event Log** - individual firewall and WAF events for a zone, newest first, with the action, service, rule, client IP, country, host, path, user agent and Ray ID, optionally filtered by action and service. Returns the latest 1,000 events in the timeframe, for up to 30 days on every plan. +- **Zone Status** - a zone's status as a health state: active is healthy; pending, initializing, read-only and paused zones are warnings; moved and deactivated zones are errors. - **Account Traffic** - requests, bandwidth and visits across every zone in an account in one query, grouped by zone, country, status code, cache status, host or device type. - **Load Balancing Requests** - load balancer request counts for a zone by load balancer, pool, origin and edge location. - **DNS Records** - every DNS record in a zone with type, content, TTL, proxy status and tags. @@ -79,7 +87,7 @@ The out-of-the-box dashboards open with a **Cloudflare Overview**, with perspect - **Worker Static Asset Requests** - requests served from a Worker's static assets, by status code, cache status or host. - **Worker Cache Requests** - Cache API requests a Worker makes, by cache status. - **Worker Smart Placement** - requests and duration for a Worker, split by whether Smart Placement ran it near its back end. -- **Workers Build Minutes** - Workers Builds minutes used by an account. +- **Worker Build Minutes** - Workers Builds minutes used by an account. - **R2 Operations** - requests and response bytes against an R2 bucket by operation type and outcome. - **R2 Storage** - stored object count, payload size, metadata size and upload count for an R2 bucket over time. - **R2 Bandwidth** - bytes downloaded from and uploaded to an R2 bucket. @@ -95,7 +103,7 @@ The out-of-the-box dashboards open with a **Cloudflare Overview**, with perspect - **Load Balancer Pool Health** - per-origin health, response code, response time and failure reason for a pool at each Cloudflare edge location. - **Access Logins** - Zero Trust login attempts for an Access application by identity provider, country and outcome. - **DNS Analytics** - authoritative DNS query volume and response time for a zone, grouped by query name, query type, response code or edge location. -- **Email Routing** - forwarded and rejected messages for a zone by action, status and rule. +- **Email Routing** - forwarded and rejected messages for a zone by action, status, SPF result or DMARC result. - **DMARC Reports** - DMARC alignment for a zone by sending source, with pass rate and message volume. - **Cache Reserve Operations** - read, write and delete operations against a zone's Cache Reserve. - **Cache Reserve Storage** - bytes and object count held in a zone's Cache Reserve over time. @@ -115,7 +123,6 @@ The out-of-the-box dashboards open with a **Cloudflare Overview**, with perspect - **Vectorize Storage** - stored vector count and dimensions for a Vectorize index. - **Hyperdrive Queries** - query volume and average latency for a Hyperdrive configuration. - **Hyperdrive Connection Pool** - pool size, free slots and waiting clients for a Hyperdrive configuration. -- **Gateway Network Sessions** - Zero Trust Gateway TCP and UDP sessions for an account by action, destination, protocol or device. - **DNS Firewall Analytics** - DNS Firewall cluster query volume, response codes and processing time for an account. - **Audit Logs** - account audit activity grouped by action, actor or resource type. - **Images Requests** - Cloudflare Images request volume for an account. @@ -213,12 +220,12 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w | Widest query / history kept | Data streams | Longest timeframe offered | | --------------------------- | ------------ | ------------------------- | | **1 day / 3 days** on Pro; none on Free | Zone Firewall Events | Last 24 hours (Last 7 and 30 days on higher plans - see below) | - | **30 days / 31 days** on every plan | Zone Firewall Event Volume | Last 30 days | + | **30 days / 31 days** on every plan | Zone Firewall Event Volume, Zone Firewall Event Log | Last 30 days | | **3 days / 3 days** | Health Check Events, Load Balancing Requests | Last 24 hours | | **7 days** | Access Logins, Network Error Logs, Page Shield Reports, Worker Cron Trigger Runs | Last 7 days | | **7 days** on Free; **30 days** on Enterprise | Turnstile Challenges | Last 7 days (Last 30 days on Enterprise Turnstile) | | **30-31 days / 31 days** | Gateway HTTP Requests and Network Sessions, Stream Playback Quality, DNS Analytics, Zone Traffic Breakdown | Last 30 days | - | **31-32 days / 31-32 days** | Gateway DNS Queries, Email Routing, DMARC Reports, Images Requests, AI Gateway Cache and Errors, AutoRAG, Browser Rendering, Container Metrics, Hyperdrive, Queue Consumer Metrics, Realtime Usage, Vectorize, Workers AI, Account Traffic, Worker Static Asset Requests, Worker Smart Placement, Workers Build Minutes, Hyperdrive Connection Pool, R2 Bandwidth | This month | + | **31-32 days / 31-32 days** | Gateway DNS Queries, Email Routing, DMARC Reports, Images Requests, AI Gateway Cache and Errors, AutoRAG, Browser Rendering, Container Metrics, Hyperdrive, Queue Consumer Metrics, Realtime Usage, Vectorize, Workers AI, Account Traffic, Worker Static Asset Requests, Worker Smart Placement, Worker Build Minutes, Hyperdrive Connection Pool, R2 Bandwidth | This month | | **32-62 days / 62-92 days** | Worker Invocations, Pages Functions, KV, D1, R2, Durable Objects, Queue Backlog and Message Operations, Pipeline Ingestion, Cache Reserve, AI Gateway Requests, DNS Firewall Analytics, Stream Minutes Viewed, Worker Subrequests, Worker Cache Requests, Queue Delayed Backlog, Durable Object Activity | Last month | | **61 days, daily only** | Images Unique Transformations | This month | | **93 days / 184 days** | Web Analytics Page Loads, Core Web Vitals, Web Analytics Page Load Timing | This quarter | @@ -229,7 +236,7 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w Limits can be wider on Business and Enterprise plans. Two streams offer timeframes that only higher plans can serve, and on a plan whose limit is shorter the tile shows an error naming that limit rather than empty data: - - **Zone Firewall Events** offers Last 7 days and Last 30 days. Its grouped dataset, `firewallEventsAdaptiveGroups`, allows 1 day on Pro and is not available on Free. Cloudflare publishes 30-31 day limits for Security Events, but [those apply to the raw event dataset](https://developers.cloudflare.com/waf/analytics/security-events/#limits), which returns individual events rather than counts. Use **Zone Firewall Event Volume** for longer ranges: its dataset counts every event for up to 30 days on every plan, including Free, but can only filter by action and service rather than break down by them. + - **Zone Firewall Events** offers Last 7 days and Last 30 days. Its grouped dataset, `firewallEventsAdaptiveGroups`, allows 1 day on Pro and is not available on Free. Cloudflare publishes 30-31 day limits for Security Events, but [those apply to the raw event dataset](https://developers.cloudflare.com/waf/analytics/security-events/#limits) behind **Zone Firewall Event Log**, which returns individual events rather than counts. For longer ranges use **Zone Firewall Event Volume**, which counts every event for up to 30 days on every plan, including Free, but can only filter by action and service rather than break down by them - or **Zone Firewall Event Log** for the individual events. - **Turnstile Challenges** offers Last 30 days, which [Cloudflare documents](https://developers.cloudflare.com/turnstile/plans/) as the Enterprise lookback; Free is limited to 7 days. To see the limits for your own account, run this in the **GraphQL Query** stream with the **None** timeframe, a `zoneTag` in **Variables**, and **Path to rows** set to `data.viewer.zones`: @@ -262,7 +269,8 @@ Worker, R2 Bucket, Vectorize Index and Worker Binding identifiers are prefixed w - **Hand-written GraphQL queries are unbounded.** The **GraphQL Query** stream runs whatever you give it, so it can hit limits the built-in streams are tuned to avoid: a large `limit` on a multi-dimension dataset can exceed the ~6 MB response cap, and a timeframe wider than that dataset's own cap fails with Cloudflare's error naming the limit. Prefer the pre-aggregated `*Groups` datasets over raw event datasets, and keep `limit` modest. The stream does not page, so your `limit` is the ceiling. - **Some analytics are only available on paid plans.** Page Shield and Network Error Logs return an authorization error on plans without them; Cache Reserve, Load Balancing and Health Checks are add-ons. A tile for a feature the zone or account is not entitled to shows Cloudflare's authorization error rather than empty data. -- **Account Traffic shows zones it cannot name by their zone tag.** The stream resolves each zone tag to an imported zone's name. Traffic for a zone the token cannot list - for example one outside the token's zone resources - appears as *Object not found: Cloudflare Zone/<tag>*. +- **Account Traffic shows zones it cannot name by their zone tag.** The stream resolves each zone tag to an imported zone's name. Traffic for a zone the token cannot list - for example one outside the token's zone resources - appears as `Object not found: Cloudflare Zone/`. +- **There is no threat-type breakdown.** Cloudflare's GraphQL Analytics API, which replaced the deprecated Zone Analytics API, does not classify threats by type. The closest equivalent is **Zone Firewall Events** grouped by **Service**, which shows which security feature acted - managed rules, rate limiting, Bot Fight Mode and so on. - **Tunnel bandwidth is not available.** Cloudflare exposes `cloudflared` traffic metrics from each connector's local metrics endpoint rather than through the API, so Tunnels show connector health only. - **Costs are unitless.** Cloudflare's AI Gateway analytics reports cost without stating a currency, so the plugin shows a plain number rather than assuming one. - **Pages Functions cannot be scoped to a single project.** Cloudflare identifies Pages Functions by an internal script name with no published mapping to the project, so this stream reports all Pages Functions in the account, with the function name as a column.