Metrics and analytics
R2 Data Catalog exposes metrics that allow you to monitor Iceberg REST API requests and table maintenance jobs (compaction and snapshot expiration) across your warehouses.
The metrics displayed in the Cloudflare dashboard are queried from Cloudflare's GraphQL Analytics API. You can access the metrics programmatically via GraphQL or any HTTP client.
R2 Data Catalog exports the below metrics within the r2CatalogDataOperationsAdaptiveGroups dataset. These metrics track Iceberg REST API requests made to your catalog, such as loading tables, listing namespaces, and committing updates.
| Metric | GraphQL Field Name | Aggregation | Description |
|---|---|---|---|
| Request count | count | count | Total number of Iceberg REST API requests |
| Request body bytes | requestBodyBytes | sum | Total bytes sent in request bodies |
| Request duration | requestDurationMs | sum, avg, quantiles | Request duration in milliseconds |
The r2CatalogDataOperationsAdaptiveGroups dataset provides the following dimensions for filtering and grouping queries:
warehouseName- The name of the R2 Data Catalog warehouseoperation- The Iceberg REST API operation name (for example,load-table,list-namespaces,commit-table)namespaceName- The Iceberg namespace targeted by the request, if applicabletableName- The Iceberg table targeted by the request, if applicablehttpStatus- HTTP response status codedatetime- Request timestampdate- Request timestamp, truncated to the start of a daydatetimeHour- Request timestamp, truncated to the start of an hourdatetimeMinute- Request timestamp, truncated to the start of a minutedatetimeFiveMinutes- Request timestamp, truncated to the start of five minutesdatetimeFifteenMinutes- Request timestamp, truncated to the start of fifteen minutes
R2 Data Catalog exports the below metrics within the r2CatalogTableMaintenanceAdaptiveGroups dataset. These metrics track table maintenance jobs including compaction and snapshot expiration.
| Metric | GraphQL Field Name | Aggregation | Description |
|---|---|---|---|
| Job count | count | count | Total number of maintenance jobs executed |
| Files processed | filesProcessed | sum | Total input files processed by maintenance jobs |
| Files output | filesOutput | sum | Total output files created by maintenance jobs |
| Input bytes | inputBytes | sum | Total bytes read or scanned by maintenance jobs |
| Output bytes | outputBytes | sum | Total bytes written by maintenance jobs |
| Job duration | jobDurationMs | sum, avg, quantiles | Job duration in milliseconds |
The r2CatalogTableMaintenanceAdaptiveGroups dataset provides the following dimensions for filtering and grouping queries:
warehouseName- The name of the R2 Data Catalog warehousejobType- The type of maintenance job (compaction,snapshot-expiration)namespaceName- The Iceberg namespace containing the tabletableName- The Iceberg table that was maintainedsuccess- Whether the job succeeded (1) or failed (0)datetime- Job timestampdate- Job timestamp, truncated to the start of a daydatetimeHour- Job timestamp, truncated to the start of an hourdatetimeMinute- Job timestamp, truncated to the start of a minutedatetimeFiveMinutes- Job timestamp, truncated to the start of five minutesdatetimeFifteenMinutes- Job timestamp, truncated to the start of fifteen minutes
You can programmatically query analytics for your R2 Data Catalog warehouses via the GraphQL Analytics API. This API queries the same datasets as the Cloudflare dashboard and supports GraphQL introspection.
R2 Data Catalog GraphQL datasets require an accountTag filter with your Cloudflare account ID.
This query returns the total number of Iceberg REST API requests and total request duration, grouped by operation, for a specific warehouse.
query CatalogDataOperations( $accountTag: String! $warehouseName: String! $datetimeStart: Time! $datetimeEnd: Time!) { viewer { accounts(filter: { accountTag: $accountTag }) { r2CatalogDataOperationsAdaptiveGroups( limit: 10000 filter: { warehouseName: $warehouseName datetime_geq: $datetimeStart datetime_leq: $datetimeEnd } ) { count dimensions { operation } sum { requestBodyBytes requestDurationMs } avg { requestDurationMs } } } }}This query returns request duration percentiles for a specific warehouse, which is useful for understanding latency distribution.
query CatalogLatencyPercentiles( $accountTag: String! $warehouseName: String! $datetimeStart: Time! $datetimeEnd: Time!) { viewer { accounts(filter: { accountTag: $accountTag }) { r2CatalogDataOperationsAdaptiveGroups( limit: 10000 filter: { warehouseName: $warehouseName datetime_geq: $datetimeStart datetime_leq: $datetimeEnd } ) { count dimensions { operation } quantiles { requestDurationMsP50 requestDurationMsP90 requestDurationMsP99 } } } }}This query returns a summary of compaction and snapshot expiration jobs for a specific warehouse, including files processed, bytes read and written, and success or failure status.
query CatalogMaintenanceMetrics( $accountTag: String! $warehouseName: String! $datetimeStart: Time! $datetimeEnd: Time!) { viewer { accounts(filter: { accountTag: $accountTag }) { r2CatalogTableMaintenanceAdaptiveGroups( limit: 10000 filter: { warehouseName: $warehouseName datetime_geq: $datetimeStart datetime_leq: $datetimeEnd } ) { count dimensions { jobType tableName success } sum { filesProcessed filesOutput inputBytes outputBytes jobDurationMs } } } }}You can narrow results to a specific Iceberg operation or table. For example, to query only load-table operations for a specific table:
query CatalogFilterByOperation( $accountTag: String! $datetimeStart: Time! $datetimeEnd: Time!) { viewer { accounts(filter: { accountTag: $accountTag }) { r2CatalogDataOperationsAdaptiveGroups( limit: 10000 filter: { warehouseName: "my-warehouse" operation: "load-table" tableName: "my_table" datetime_geq: $datetimeStart datetime_leq: $datetimeEnd } ) { count sum { requestDurationMs } } } }}To query only failed maintenance jobs:
query CatalogFailedMaintenanceJobs( $accountTag: String! $datetimeStart: Time! $datetimeEnd: Time!) { viewer { accounts(filter: { accountTag: $accountTag }) { r2CatalogTableMaintenanceAdaptiveGroups( limit: 10000 filter: { warehouseName: "my-warehouse" success: 0 datetime_geq: $datetimeStart datetime_leq: $datetimeEnd } ) { count dimensions { jobType tableName } } } }}To query metrics across all warehouses on an account, omit the warehouseName filter and include warehouseName in the dimensions:
query CatalogAllWarehouses( $accountTag: String! $datetimeStart: Time! $datetimeEnd: Time!) { viewer { accounts(filter: { accountTag: $accountTag }) { r2CatalogDataOperationsAdaptiveGroups( limit: 10000 filter: { datetime_geq: $datetimeStart, datetime_leq: $datetimeEnd } ) { count dimensions { warehouseName operation } sum { requestDurationMs } } } }}