Skip to content

Signals

All signals carry service.name=cf2otel. Cloudflare-specific names begin cloudflare.*; GenAI names follow gen_ai.*; the poller's own measurements begin cf2otel.*. Names are declared in internal/semconv and this page is the public inventory.

Cloudflare physical-request self-metrics

cf2otel.api.requests is a monotonic Counter with unit {request}; cf2otel.api.duration and cf2otel.api.limiter_wait are Histograms with unit s. Each physical HTTP exchange records exactly one count and one sample in both histograms, including REST pagination, GraphQL settings and query calls, retry attempts and followed redirect hops. A cache hit makes no HTTP request and records nothing. Cancellation while acquiring quota also records nothing. The existing read-only guard, limiter rate, retries and collector cadence are unchanged.

These three metrics carry only cf2otel.collector (the scheduler's registered collector name, or unattributed outside scheduled/one-shot/range collection), cf2otel.api.method (rest or graphql) and, only on a failed HTTP exchange, cf2otel.error.class. HTTP 429 is rate_limited, HTTP 401/403 is auth, context deadlines and network timeouts are timeout, and other transport errors or HTTP 4xx/5xx responses are other. Followed HTTP redirects and HTTP 2xx responses carry no error class. Logical errors in HTTP 2xx envelopes, body reads and schema decoding are not transport-header outcomes; collector scrape errors and the separate envelope-error metric retain their existing semantics. No HTTP verb, route, URL, scope ID, query, status code or response/error text is an attribute on these three metrics. Registered collector names are trusted application identifiers, never populated from upstream responses.

Duration runs from the start of the HTTP call through response headers or a transport error. Limiter wait measures that hop's process-budget acquisition before the HTTP call (including the negligible immediate-acquisition time), excluding retry backoff and response-body processing. Both use the explicit second boundaries: 0.25, 0.5, 1, 1.5, 2, 3, 4, 5, 7.5, 10, 15, 20, 30, 45, 60, 90, 120. Metrics emit directly, even when the collector later fails or retains its checkpoint; they do not measure successful logical polls or rows. Existing cf2otel.api.request spans and cf2otel.api.retries retain their status-class attributes; spans retain the HTTP verb on cf2otel.api.method. Aggregate request queries remain valid, but the old request/duration cf2otel.status_class dimension is replaced by the bounded dimensions above.

Source deny-lists

The source deny-list settings use exact semantic names from this inventory before Prometheus translation. otlp.metric_denylist suppresses SDK registration/observation; otlp.attribute_denylist removes keys from every signal attribute bag, including generated event_name and nested span bags, but not resources or bodies. Both default to empty. Denying event_name removes the usual event-name log query selector, not the log signal. Dropping dimensions merges counter/histogram series and loses their distinction; gauge and retained-snapshot collisions use the last input point. Denying metrics does not disable their collectors or upstream reads.

Public vendor status

Both public status collectors are opt-in and off by default. They use an isolated unauthenticated HTTP client, not the tenant Cloudflare API client.

NameKind / unitMeaning
cloudflare.status.component.statusGauge / 1Current component status: 0 operational, 1 under_maintenance, 2 degraded_performance, 3 partial_outage, 4 major_outage, 5 unknown. Unknown strings are never treated as healthy.
cloudflare.status.incident.updateLog eventUpdates from the 50 latest incidents, including resolved incidents; timestamp is source updated_at, strictly newer than the checkpoint and no later than the source bound (from,to]. Best-effort, not a complete historical feed.

The gauge carries only string cloudflare.status.component.name (public vendor name) and cloudflare.status.component.type (group, component, or reserved remainder). Distinct (name,type) labels are sorted lexically; duplicates take the worst numeric status. Up to statuspage.component_cap ordinary series (default 500) are retained, plus one name=other,type=remainder series with the worst status of all overflow rows. The reserved type cannot collide with real components named other. No component IDs or guessed region labels are emitted; status codes are not averaged. A successful full snapshot replaces all points, including clearing retired components or a valid empty array. TTL is three configured polling intervals; failed reads do not refresh it. Absence or expiry is unavailable state, not proof of health.

Incident logs carry string attributes cloudflare.status.incident.id, .name, .status, .impact, and cloudflare.status.update.id, .status. These identifiers never become metric labels. Body text is capped at 8192 UTF-8 bytes without splitting a rune. cloudflare.status.update.truncated is the string enum "true" when clipped; an unclipped body leaves it absent (consumers may also accept "false"). It is not a boolean attribute. Duplicate update IDs at the same source timestamp emit once per response, while edited revisions with a new timestamp emit separately. There is no publication-latency holdback or persistent seen-ID ledger. Successful commits advance the durable checkpoint to the source bound (UTC seconds), including empty polls; restarting with FileStore does not reemit committed updates. Newly visible updates whose updated_at is at or older than that checkpoint are intentionally not emitted. Late older updates may therefore be missed even while still on the latest page. A newer revision after restart is emitted. Selected updates retain the scheduler's at-least-once commit semantics; partial export/checkpoint failures can replay them.

Components and incident windows are independent: a valid component snapshot can publish while incident delivery is unavailable. Neither channel establishes the other's freshness. The vendor's latest-50 limit can permanently omit off-page updates after an outage or a busy period. No complete backfill or arbitrary-latency once-only guarantee is claimed. The Workers and platform dashboard tab includes a component status table and an incident-update log panel with all status attributes. Prometheus translates the unit-1 gauge to cloudflare_status_component_status_ratio; the suffix does not mean an availability ratio. Its instant query may retain a last sample during Prometheus lookback after SDK snapshot expiry. No live runtime enablement or dashboard provisioning is implied.

Zone selection and poll gauges

zones.exclude (or comma-separated CF2OTEL_ZONES__EXCLUDE) defaults to empty. Selectors match exact zone IDs or case-insensitive zone names, with no regex or wildcard expansion. Each zone consumer first applies its existing include and account-ownership rules and validates them, then removes excluded zones. An unmatched exclusion is ignored; an unmatched include still has its existing behavior. A valid selection entirely removed by exclusions is a successful empty zone poll. Account-level queries, including Logpush's account scope, are unchanged.

The four cf2otel.zones.* gauges use only cf2otel.collector; filtered and skipped also use cf2otel.zone.reason. Reasons are bounded to include, exclude, unentitled, no_account, and other. Discovered counts the API discovery result; filtered counts zones removed by selection; processed counts distinct zones actually queried, not settings reads, query subdivisions, or datasets; skipped counts remaining eligible zones not queried. No zone name or ID is a gauge label. Every successful complete poll emits zero for absent reason series. Failed polls retain the existing no-partial-output behavior and do not refresh these gauges.

WARP recently seen fleet

cloudflare.warp.devices is a Gauge with unit 1, from account-scoped GET /accounts/{account}/dex/fleet-status/devices, source last_seen. It counts unique devices within warp.last_seen_window (default 15 minutes, maximum 60), not the total physical or licensed fleet. Network status strings are preserved as observed; there is no documented connected/active Boolean classification.

Its five string dimensions are cloudflare.warp.status, cloudflare.warp.platform, cloudflare.warp.client_version, cloudflare.warp.mode, and cloudflare.warp.colo. A sixth string attribute, cloudflare.warp.remainder, is false on normal tuples and true on overflow. Normal tuples are sorted lexically, retaining the first warp.max_metric_series (default 500); excess tuples and tuples containing a dimension longer than 256 bytes are summed into one all-other remainder. This preserves the device total and distinguishes a real all-other tuple from overflow. Empty dimension strings remain observed empty strings. No device ID, user identity, timestamp, raw body, log, trace or additional metric is emitted. IDs exist only during a poll for identical-tuple deduplication; conflicting duplicate IDs fail the whole snapshot.

Pages are fetched in ascending order, respecting a server page size at most 50, until a short/empty page (including an empty read after a full final page). Reported totals are not completion proof. Invalid/missing/null required strings, malformed arrays, HTTP failures, mismatched paging, stalled full pages or the 10,000-page/100,000-unique-device safety bounds fail without partial publication or expiry refresh. Successful empty arrays clear previous points; successful snapshots expire after three actual configured collector intervals.

This opt-in collector uses the existing expiring SDK snapshot batch emitter, never ordinary cumulative Gauge fallback. The row shape is doc-derived from the official device method and pinned by local fixtures. The root's current canary observed only successful empty rows (doc-0003, section 16); populated rows and real fleet pagination are not live-verified. Dashboard delivery is a separate pending work item.

DEX test results

The opt-in dex.tests snapshot collector emits the following Gauges from provider .avg values. It does not recompute slot statistics or query individual hops.

MetricUnitProvider field
cloudflare.dex.http.fetch_timemshttpStats.resourceFetchTimeMs.avg
cloudflare.dex.traceroute.rttmstracerouteStats.roundTripTimeMs.avg
cloudflare.dex.traceroute.hops{hop}tracerouteStats.hopsCount.avg; the average can be fractional
cloudflare.dex.packet_loss%tracerouteStats.packetLossPct.avg; percentage, not a fraction
cloudflare.dex.availability%httpStats.availabilityPct.avg or tracerouteStats.availabilityPct.avg

All points have only string attributes cloudflare.dex.test.name and cloudflare.dex.test.kind (http or traceroute). No account, device or test ID, URL, address, raw body, log or trace is exported. A named test must start with an ASCII letter and contain only ASCII letters, digits, spaces, underscores and hyphens, at most 128 characters; reserved other and other names go to the remainder. Operators must still avoid sensitive names. Duplicate name/kind pairs with distinct IDs fail catalog enumeration instead of merging or labeling by ID.

dex.max_metric_series bounds sticky named identities plus six reserved signal/kind remainders across polls until restart. Overflow points have test name other and preserve test kind. Their value is the arithmetic mean of the available per-test provider averages for that signal/kind, not a weighted fleet statistic. Missing/null optional averages are omitted, not fabricated as zero; finite nonnegative values are required, with percentages at most 100. Invalid results fail only that test. See configuration for cap allocation, failure isolation and expiry semantics.

The catalog is GET /accounts/{account}/dex/tests/overview, with tests[] containing id, name and kind, fully enumerated at 50 rows per page. Detail reads use GET /accounts/{account}/dex/http-tests/{test} or GET /accounts/{account}/dex/traceroute-tests/{test}, with UTC millisecond ISO from/to and interval=minute. The default result window is one hour, bounded to seven days, with no detail pagination. Provider averages keep their documented units exactly. Shapes come from the official HTTP test result method and traceroute result method, and are proved locally with fixtures, a real shared HTTP client and the SDK. The drift contract registers all three paths but reports both detail templates as documented_only, unprobed; no live tests exist. Only the list endpoint canary is live-probed. Populated/live-runtime proof and dashboard panels remain separate root-owned work; this source does not claim full task acceptance.

Workers AI aggregate metrics

The opt-in workersai.metrics collector reads account-scoped aiInferenceAdaptiveGroups, not raw inference rows. It emits additive Counters from complete UTC five-minute half-open buckets, with no metric attributes:

MetricUnitSource
cloudflare.workers_ai.inferences1count, total number of inferences for an account
cloudflare.workers_ai.input_tokens{token}sum.totalInputTokens
cloudflare.workers_ai.output_tokens{token}sum.totalOutputTokens
cloudflare.workers_ai.inference_timessum.totalInferenceTimeMs divided by 1000

Count and bucket time are required; optional sums are selected only when advertised and within the field limit. Missing/null optional values are omitted, not zero-filled. Empty windows emit no fabricated metrics. Counts and sums add across successful windows; a malformed value or saturated single bucket fails the whole window without checkpoint advancement or partial publication. Query limits and dataset duration/retention are respected, with saturated windows bisected at five-minute boundaries. The existing platform series cap applies. No model/resource ID, tag, cost, byte metric, log or trace is selected or emitted.

The scheduler holds back ten minutes and aligns its upper bound to a complete five-minute bucket. This is operational policy, not a guarantee of ingestion latency or recovery of late arrivals after a checkpoint has advanced. Dashboard panels and live canary/proof delivery are separate root-owned work.

Logs and traces

Event or spanSourceNotes
cloudflare.status.incident.updatePublic Status API /api/v2/incidents.jsonLatest 50 incidents including resolved updates; UTC source timestamp, log-only IDs and UTF-8-bounded body.
cloudflare.tunnel.status_changeTunnel REST snapshotID, name, status and previous status; first poll emits none. (CFO-0048.01)
cloudflare.access.loginAccess REST request logLogin action, decision (cloudflare.access.allowed: true/false), app, uppercase ISO 3166-1 alpha-2 country and available identity details. The source has short history.
cloudflare.access.scim_updateAccess SCIM update logResource type, HTTP method, status and available identifiers.
cloudflare.http.requesthttpRequestsAdaptiveSampled per-request event. Access user identity, when present, is inferred and flagged.
cloudflare.ai_gateway.requestAI Gateway REST logsRequest metadata and outcome. Request and response content is optional and capped.
gen_ai.client.inference.operation.detailsAI Gateway body contentOpt-in span event and correlated OTLP content log per available side, subject to the body cap.
cloudflare.audit.eventAccount audit log v2Actor, action, resource and request details. Email and IP are log attributes only.
cloudflare.firewall.eventfirewallEventsAdaptivePer-request security action; IP, path, query, user agent and ray stay on logs.
cloudflare.dns.querydnsAnalyticsAdaptivePer-query DNS event with available query, response and network fields. Names and IPs stay on logs.
cf2otel.window.gapRetention-gap handlingCollector, skipped window and retention floor when a source cannot backfill.
cf2otel.process.logcf2otel's own process logEvery record at or above log.level, with its severity; the body is the JSON-encoded record (message and fields, including error text). Batched apart from checkpoint commits, so a lost record never fails a commit. Query with {service_name="cf2otel"} \| event_name="cf2otel.process.log".
GenAI client spanAI Gateway REST logsRequest model/provider, outcome, token usage and available timing.
cf2otel.api.requestCloudflare API clientAttempt duration, method and status class; no URL or scope identifier.

Loki stores the OTLP log attributes as structured metadata. Filter from {service_name="cf2otel"}, then use | event_name="cloudflare.http.request" or another event value. Paths, IPs, emails, user agents and ray IDs stay on logs or spans, never on metric series.

Extension declarations (collector implementations pending)

These declarations reserve the following signals; this seam-only change does not emit them. Existing outputs remain unchanged. Every selection uses advertised settings.availableFields names in part_field form and respects field budgets, maxDuration and notOlderThan. Health checks are disabled on Free and enabled on the verified Pro plan; disabled scopes are skipped, not queried. HTTP visits are available on Free/Pro adaptive Groups. Threat rollups have observed retention of about three days on Free and seven days on Pro, with a three-day maximum query duration on both. Account adaptive HTTP settings permit 32 days, sufficient for a 31-day UTC month. Zone Logpush settings permit one day on Free and seven on Pro (retention includes about one extra hour); account Logpush permits about 30 days. Account DO/D1/Queue settings permit 32-day windows and 90-day retention. These are observed plan settings, not universal guarantees; runtime settings remain authoritative. No new permission or resource is provisioned.

NameKind / unitMeaning
cloudflare.logpush.failed_uploadsCounter / {upload}Upload failures by scope, zone name for zone scope, job ID, destination type, status code and final attempt. Source success/final are uint8 flags, job ID is uint64; success=0 means failure, final=1 with status>=300 means final loss. Explicit opt-in and platform cap; old uploads/records unchanged. (CFO-0047.03)
cloudflare.http.visitsCounter / {visit}Additive sum.visits, zone only, inside existing adaptive Groups metrics with configured request-source policy. (CFO-0046.05)
cloudflare.http.threatsCounter / {request}sum.threats from complete UTC-hour rollups, held back at least ten minutes; zone only, not assumed eyeball-filterable. (CFO-0046.05)
cloudflare.http.account.transfer.month_to_dateGauge / ByUTC month-to-date eyeball response bytes through latest held-back complete five-minute end; no account ID/host. Snapshot without checkpoint. Successful empty results mean zero; errors/null do not. (CFO-0046.05)
cloudflare.http.account.transfer.projected_month_totalGauge / ByMTD bytes * exact UTC month seconds / elapsed complete-period seconds; zero when no complete elapsed period, including month rollover. Always eyeball-only. (CFO-0046.05)
cloudflare.durableobjects.errorsCounter / {error}Invocation error sum by bounded Workers script name; old request totals preserved. (CFO-0047.02)
cloudflare.durableobjects.wall_timeGauge / sLatest complete five-minute script bucket wall-time p50/p75/p99/p999, microseconds to seconds; never combine status-group quantiles. (CFO-0047.02)
cloudflare.durableobjects.response_sizeGauge / ByLatest complete five-minute script bucket responseBodySize p50/p75/p99/p999, bytes. No namespace/object IDs. (CFO-0047.02)
cloudflare.d1.rows_readCounter / {row}Account aggregate rows read, no database ID. (CFO-0047.02)
cloudflare.d1.rows_writtenCounter / {row}Account aggregate rows written, no database ID. (CFO-0047.02)
cloudflare.d1.query.batch_timeGauge / sLatest complete account bucket queryBatchTimeMs p50/p75/p99/p999, milliseconds to seconds. (CFO-0047.02)
cloudflare.d1.query.batch_response_sizeGauge / ByLatest complete account bucket queryBatchResponseBytes p50/p75/p99/p999. No query text/identifier. (CFO-0047.02)
cloudflare.queues.message.max_queue_avg_lagGauge / sLatest observed complete bucket maximum of per-queue average lag, ReadMessage only; milliseconds to seconds, no queue ID. Not a universal snapshot-retirement policy. (CFO-0047.02)
cloudflare.queues.message.max_queue_avg_retriesGauge / {retry}Latest observed complete bucket maximum of per-queue average retries, ReadMessage only; no queue ID. Missing/negative N/A values omitted, real zero retained. (CFO-0047.02)
cloudflare.queues.message.billable_operations.by_actionCounter / {operation}sum.billableOperations by action type, consumer type and outcome; no queue ID, old aggregate unchanged. (CFO-0047.02)
cloudflare.health_check.eventsCounter / {event}Pro-only opt-in event count by zone name, source healthStatus string and failure reason; separate from timing grouping. (CFO-0050.03)
cloudflare.health_check.rttGauge / sLatest complete per-origin bucket average rttMs / 1000, bounded non-IP identity; omit absent/N/A, no fabricated zero. (CFO-0050.03)
cloudflare.health_check.ttfbGauge / sLatest complete per-origin bucket average timeToFirstByteMs / 1000. (CFO-0050.03)
cloudflare.health_check.tcp_connectionGauge / sLatest complete per-origin bucket average tcpConnMs / 1000. (CFO-0050.03)
cloudflare.health_check.tls_handshakeGauge / sLatest complete per-origin bucket average tlsHandshakeMs / 1000. (CFO-0050.03)
AttributeMeaning
cloudflare.logpush.scopeaccount or zone. (CFO-0047.03)
cloudflare.logpush.zoneZone name, never account/zone ID. (CFO-0047.03)
cloudflare.logpush.job_idSource numeric job ID; explicit opt-in and platform cap. (CFO-0047.03)
cloudflare.logpush.destination_typeBounded source destination type. (CFO-0047.03)
cloudflare.logpush.status_codeSource destination status code as string. (CFO-0047.03)
cloudflare.logpush.final_attempttrue/false from source final 0/1. (CFO-0047.03)
cloudflare.queues.action_typeSource action type. (CFO-0047.02)
cloudflare.queues.consumer_typeSource consumer type. (CFO-0047.02)
cloudflare.queues.outcomeSource outcome. (CFO-0047.02)
cloudflare.health_check.zoneZone name. (CFO-0050.03)
cloudflare.health_check.statusSource string healthStatus, not an invented boolean mapping. (CFO-0050.03)
cloudflare.health_check.failure_reasonBounded source reason; empty maps to none. (CFO-0050.03)
cloudflare.health_check.originNon-IP FQDN or human health-check name, bounded to 128 characters; no originIP/raw resource ID, omit timings without usable identity. (CFO-0050.03)
cloudflare.workers.script_name (reused by DO)Bounded script name; omit new per-script points when unavailable. (CFO-0047.02)
cloudflare.statistic (reused by DO/D1)p50/p75/p99/p999 for extension quantiles; old statistic values unchanged. (CFO-0047.02)

Metrics

The seat source is GET /accounts/{account}/access/users. Cloudflare's official Go SDK AccessUserListResponse defines access_seat and gateway_seat as boolean flags, separately from active device count. cf2otel preserves field presence: false is valid, but missing, null and nonboolean flags fail the scrape. Each successful full-list scrape emits exactly two gauge points, including two zeros for a genuinely empty list. A user with both flags contributes one to each type. Existing cloudflare.access.users inventory is unchanged.

NameUnitMeaning
cloudflare.http.response.bytesByResponse byte count on the HTTP request dimensions. (CFO-0046.01)
cloudflare.http.edge.ttfbsEdge time to first byte by zone, host and statistic (avg, p50, p95, p99); Pro only. (CFO-0046.04)
cloudflare.http.origin.response_timesOrigin response time by zone, host and statistic (p50, p95, p99). (CFO-0046.04)
cf2otel.http.latency.host_variantsCounter / {group}Discarded latency source groups whose raw hosts normalize to the same host, zone only. Timings come from the largest-count group; equal counts prefer the raw host equal to the normalized host (then lexical raw-host order). Percentiles are never summed or averaged. Request, byte and breakdown totals remain additive across all groups. A latency query/validation failure fails the buffered window explicitly with its checkpoint unchanged, preserving all totals for retry.
cloudflare.http.requests.by_status{request}Request count by enabled edge and origin status. Zone-level, without host. (CFO-0046.02)
cloudflare.http.requests.by_country{request}Request count by client country. Zone-level, without host. (CFO-0046.02)
cloudflare.http.requests.by_protocol{request}Request count by enabled HTTP and TLS protocol. Zone-level, without host. (CFO-0046.02)
cloudflare.http.requests.by_method{request}Request count by HTTP method. Zone-level, without host. (CFO-0046.02)
cloudflare.http.requests.by_content_type{request}Request count by response content type. Zone-level, without host. (CFO-0046.02)
cloudflare.http.response.bytes.by_countryByResponse byte count by zone and client country, without host. (CFO-0046.02)
cloudflare.workers.invocations{request}Invocation count by script name and status. (CFO-0047.01)
cloudflare.workers.errors{error}Invocation error count by script name. (CFO-0047.01)
cloudflare.workers.subrequests{request}Subrequest count by script name. (CFO-0047.01)
cloudflare.workers.cpu_timesCPU time by script name and statistic (p50, p75, p99, p999). (CFO-0047.01)
cloudflare.workers.wall_timesWall time by script name and statistic (p50, p75, p99, p999). (CFO-0047.01)
cloudflare.workers.request_durationsRequest duration by script name and statistic (p50, p75, p99, p999). (CFO-0047.01)
cloudflare.certificate.pack{pack}Present certificate packs (value 1), including packs with unknown expiry; latest complete snapshot only, expiring after three collector intervals.
cloudflare.certificate.expirysSeconds until the earliest certificate expiry in a pack at collection time; negative once expired. Latest complete snapshot only, expiring after three collector intervals; packs with unknown expiry are omitted. (CFO-0050.01)
cloudflare.tunnel.status{tunnel}Current tunnel status gauge with value 1, by id, name and status. (CFO-0048.01)
cloudflare.tunnel.connections{connection}Active tunnel connections by id, name and colo. (CFO-0048.01)
cloudflare.tunnel.connectors{connector}Tunnel connectors by id, name and connector version. (CFO-0048.01)
cf2otel.metric.cardinality_overflows{datapoint}SDK overflow datapoints observed per export, by cf2otel.instrument. Cumulative overflow series are counted each time they are exported; the counter appears on the next collection. A warning names each overflowing instrument at most once per hour. (CFO-0045)
cf2otel.identity.outcomes{request}Monotonic counter of identity inference outcomes, grouped by cf2otel.identity.outcome (matched, unmatched, ambiguous). Records only new outcomes each poll, not repeated cumulative snapshots; resets on process restart. Replaces the three cf2otel.identity.matched / unmatched / ambiguous gauges. (CFO-0058)
cloudflare.access.logins1Human Access login count from cf1AccessLoginsRawGroups; cloudflare.access.allowed is normalized from the source decision to true/false, matching every Access signal.
cloudflare.access.identity_logins1Exact REST identity-login count by app, allowed, connection and action; excludes nonidentity service-token rows.
cloudflare.access.requests{request}Access request count from accessLoginRequestsAdaptiveGroups; keep nonidentity traffic separate.
cloudflare.access.apps1Access application inventory gauge.
cloudflare.access.users1Access user inventory gauge.
cloudflare.access.seats1Current user seat gauge by independent access or gateway type; overlapping types are not an additive billing-user total.
cloudflare.http.requests{request}Request count from sample-corrected httpRequestsAdaptiveGroups.
cloudflare.http.origin.durationsAverage origin response duration per Groups window, in seconds.
cloudflare.audit.events1Exact audit event count by resource product, action type and action result.
cloudflare.firewall.events{event}Security event count from a Groups dataset by zone and available action/source. Optional rule ID/description, host and client country replace the default dimension set when firewall.rule_dimensions is enabled; the total per-window collector cap includes an all-other remainder. ByTimeGroups omits action/source, but may include advertised bot fields. cloudflare.firewall.bot_score_bucket and cloudflare.firewall.bot_score_source are selected by default only when advertised by the selected zone's actual dataset and when the field budget permits after existing fields. Buckets are exporter-defined width-10 numeric intervals over the uint8 domain: 0-9, 10-19, ... 240-249, 250-255. These are NOT vendor bot/human classifications or sentinel meanings. Only nonnegative integral scores in 0..255 are accepted; invalid, missing or null scores omit the bucket, while real zero belongs to 0-9. Source names pass through as valid UTF-8 with no controls and at most 128 characters; a collector-lifetime sticky budget retains 32 normal names plus other, without enum guesses or identifier fallback. The existing default 500-series whole-attribute-set window cap includes bot dimensions and a count-conserving all-other remainder. Unadvertised or budget-skipped bot fields never prevent base counts or complete-window checkpoint advancement.
cloudflare.dns.queries1DNS query count from dnsAnalyticsAdaptiveGroups by zone and available query type, response code, cached/stale flags and protocol. Colo is omitted from metrics and remains on cloudflare.dns.query events. A collector-lifetime global budget admits at most 9998 normal attribute sets at default config and reserves one series containing only cloudflare.dns.zone="<aggregated>" for all other counts. Admissions are sticky across windows because the SDK retains cumulative series. The fallback preserves totals but loses every breakdown, including zone. Folding logs a warning naming this instrument at most once per hour; it is collector coalescing, not SDK overflow, and does not carry otel.metric.overflow. (CFO-0045)
cloudflare.gateway.dns.queries1Gateway DNS query sum from account-level cf1GatewayDnsRawGroups, by bounded query type, resolver decision and country.
cloudflare.rum.page_views1Page views from rumPageloadEventsAdaptiveGroups by country and device.
cloudflare.rum.sessions1Visit sum from rumPageloadEventsAdaptiveGroups by country and device.
cloudflare.rum.lcp.p75sRolling p75 largest contentful paint gauge, converted from GraphQL microseconds to seconds.
cloudflare.rum.inp.p75sRolling p75 interaction to next paint gauge, converted from GraphQL microseconds to seconds.
cloudflare.rum.fid.p75sRolling p75 first input delay gauge, converted from GraphQL microseconds to seconds.
cloudflare.rum.fcp.p75sRolling p75 first contentful paint gauge, converted from GraphQL microseconds to seconds.
cloudflare.rum.ttfb.p75sRolling p75 time to first byte gauge, converted from GraphQL microseconds to seconds.
cloudflare.rum.cls.p751Rolling p75 cumulative layout shift score gauge.
cloudflare.workers.requests{request}Worker request count from workersOverviewRequestsAdaptiveGroups, optionally by bounded script name.
cloudflare.turnstile.events1Turnstile event count from turnstileAdaptiveGroups, account aggregate.
cloudflare.logpush.uploads1Logpush upload count from logpushHealthAdaptiveGroups, account aggregate.
cloudflare.logpush.records1Logpush record count from logpushHealthAdaptiveGroups, account aggregate.
cloudflare.d1.read_queries1D1 read query sum from d1AnalyticsAdaptiveGroups, by bounded database name.
cloudflare.d1.write_queries1D1 write query sum from d1AnalyticsAdaptiveGroups, by bounded database name.
cloudflare.d1.queries1D1 query count from d1QueriesAdaptiveGroups by bounded database name; query text is not selected.
cloudflare.d1.storage.max_database_bytesByMaximum D1 database size across databases in the latest complete bucket, By.
cloudflare.kv.requests{request}KV operation request sum from kvOperationsAdaptiveGroups, by bounded namespace name.
cloudflare.kv.storage.max_namespace_bytesByMaximum KV namespace bytes in the latest complete bucket, By.
cloudflare.kv.storage.max_namespace_keys{key}Maximum KV namespace key count in the latest complete bucket.
cloudflare.r2.bandwidth.download.bytesByR2 download byte sum, optionally by bounded bucket name, By.
cloudflare.r2.bandwidth.upload.bytesByR2 upload byte sum, optionally by bounded bucket name, By.
cloudflare.r2.catalog.data.operations1R2 catalog data operation count, optionally by bounded namespace name.
cloudflare.r2.catalog.maintenance.jobs1R2 catalog maintenance job count, optionally by bounded namespace name.
cloudflare.r2.requests{request}R2 operation request sum by advertised action type and optional bucket name, bounded by complete attribute set.
cloudflare.r2.storage.payload.bytesByR2 payload-size gauge in the latest complete bucket per bucket, By.
cloudflare.r2.storage.objects{object}R2 object-count gauge in the latest complete bucket per bucket.
cloudflare.r2sql.queries1R2 SQL query count, optionally by bounded bucket name; table names are omitted.
cloudflare.durableobjects.requests{request}Durable Objects invocation request sum by bounded namespace name.
cloudflare.durableobjects.subrequests{request}Durable Objects periodic subrequest sum by bounded namespace name.
cloudflare.durableobjects.sql_storage.max_namespace_bytesByMaximum Durable Objects SQL storage across namespaces in the latest complete bucket, By.
cloudflare.durableobjects.subrequests.request_body.bytesByDurable Objects uncached request-body byte sum by bounded namespace name, By.
cloudflare.queues.backlog.max_queue_avg_messages{message}Maximum per-queue average backlog messages in the latest complete bucket.
cloudflare.queues.backlog.max_queue_avg_bytesByMaximum per-queue average backlog bytes in the latest complete bucket, By.
cloudflare.queues.consumer.max_queue_avg_concurrency{consumer}Maximum per-queue average consumer concurrency in the latest complete bucket.
cloudflare.queues.delayed_backlog.max_queue_avg_messages{message}Maximum per-queue average delayed backlog messages in the latest complete bucket.
cloudflare.queues.message.operations1Queue message operation count by bounded resolved queue name.
cloudflare.queues.message.billable_operations1Queue billable operation sum by bounded resolved queue name.
cloudflare.email.routing.events1Email Routing Groups count summed across account-owned zones, account aggregate.
cloudflare.email.sending.events1Email Sending Groups count summed across account-owned zones, account aggregate.
cloudflare.ai_gateway.requests{request}AI Gateway request count.
cloudflare.ai_gateway.errors1AI Gateway error count.
cloudflare.ai_gateway.body_non_json{request}Non-JSON bodies omitted from content export, counted per cloudflare.ai_gateway.body.side (request or response); metadata export continues.
cloudflare.ai_gateway.cache_hits1AI Gateway cache hits.
cloudflare.ai_gateway.cost1AI Gateway request cost.
cloudflare.ai_gateway.dlp.requests{request}AI Gateway request count with a DLP outcome (flagged, blocked or other), by gateway, action and direction; one count per distinct request/response direction, or other when the action carries no findings.
cloudflare.ai_gateway.log_coverage.gap{request}Gauge: aiGatewayRequestsAdaptiveGroups request count minus REST log count for one closed five-minute window, by cloudflare.ai_gateway.gateway.name. A completeness check on the REST log source, not a request rate. Off by default.
gen_ai.client.operation.durationsGenAI operation duration.
gen_ai.client.inference.usage.input_tokens{token}Input token usage.
gen_ai.client.inference.usage.output_tokens{token}Output token usage.
gen_ai.client.inference.usage.cache_read.input_tokens{token}Cached input tokens.
gen_ai.client.inference.usage.reasoning.output_tokens{token}Reasoning output tokens.
gen_ai.client.inference.operation.input_tokens{token}Input tokens by operation.
gen_ai.client.inference.operation.output_tokens{token}Output tokens by operation.
cf2otel.scrape.success1Collector scrape success state.
cf2otel.zones.discovered{zone}Zones returned by discovery for a complete collector poll.
cf2otel.zones.filtered{zone}Zones removed by include, ownership or exclusion selection, by reason.
cf2otel.zones.processed{zone}Distinct eligible zones queried in a complete collector poll.
cf2otel.zones.skipped{zone}Eligible zones not queried in a complete collector poll, by reason. unentitled includes disabled/absent zone datasets during cloudflare.entitlement_backoff; no zone or dataset ID labels.
cf2otel.scrape.durationsCollector scrape duration. Explicit histogram boundaries in seconds: 0.25, 0.5, 1, 1.5, 2, 3, 4, 5, 7.5, 10, 15, 20, 30, 45, 60, 90, 120.
cf2otel.scrape.errors1Collector scrape errors.
cf2otel.scrape.last_success_timestampsTime of last successful collector scrape.
cf2otel.export.success1Successful OTLP exports.
cf2otel.export.errors1Failed OTLP exports.
cf2otel.build.info1Build identity.
cf2otel.process.start_timesUnix time the cf2otel process started.
cf2otel.scrape.intervalsActual registered polling interval, per collector.
cf2otel.scrape.elapsedsMaximum of active poll elapsed time and last completed poll duration, per collector. A new poll does not hide the previous overrun; a faster completion clears it.
cf2otel.checkpoint.backlogsCheckpoint age beyond current source holdback (including dynamic bucket alignment), clamped to zero; only window collectors with an observed checkpoint. Initial/restored cursors are observed before fetching, even when the first pull stalls.
cf2otel.checkpoint.agesAge of the oldest collector checkpoint.
cf2otel.api.requests{request}Physical Cloudflare HTTP exchanges by scheduler collector, rest/graphql method and failure-only error class.
cf2otel.api.envelope_errors{error}Logical errors in unsuccessful Cloudflare API envelopes returned with successful HTTP status. Certificate pack permission code 9109 increments once with cf2otel.status_class=4xx; the physical HTTP 2xx request carries no error class. HTTP 403 is counted only by the shared HTTP request observer with error class auth, not by this counter.
cf2otel.api.durationsPhysical Cloudflare HTTP duration through response headers, excluding limiter wait; same dimensions as cf2otel.api.requests. Explicit histogram boundaries in seconds: 0.25, 0.5, 1, 1.5, 2, 3, 4, 5, 7.5, 10, 15, 20, 30, 45, 60, 90, 120.
cf2otel.api.limiter_waitsProcess-budget acquisition duration for each physical HTTP exchange; same dimensions and explicit histogram boundaries as cf2otel.api.duration.
cf2otel.api.retries1Cloudflare API retries.
cf2otel.window.gapsSkipped retention-gap seconds by collector.
cf2otel.window.commit_failures1Failed window commits by retry or dropped outcome.
cf2otel.window.catchup_windows1Additional bounded collector windows committed in one scheduler tick.

Platform gauges select the latest complete five-minute source bucket and emit at export time. D1, KV, Durable Objects and Queue base gauges use the globally latest bucket across resources, then MAX within each resolved name or remainder; older resource buckets are not carried forward. R2 keeps its per-resource latest-bucket behavior. Base counters SUM within each resolved name or remainder. Queue averages still require the advertised queue ID for correct per-queue statistics; missing required fields fail before query, emission or checkpoint advancement. The emitter attaches the listed UCUM units to OTLP instruments. RUM timing values are converted from source microseconds to seconds before recording. The GenAI operation histogram and poller API/scrape histograms use explicit second-based buckets, including sub-second boundaries. Scrape duration includes 300-second and longer boundaries through 7200 seconds, so polls exceeding the five-minute cadence remain measurable; API request and limiter-wait boundaries are unchanged. Queue IDs are used only inside source aggregation and are never metric attributes.

Prometheus compatibility naming adds _seconds for s when the base name lacks it and _ratio for dimensionless gauges. Names already ending in _bytes retain that suffix, and annotated {token} and {request} units add no suffix. The generated Grafana dashboard (dashboards/cf2otel.json, built by grafana/build_dashboard.py) queries only the suffixed names.

AI Gateway metrics combine Cloudflare request outcome measurements with GenAI duration and usage conventions.

AI Gateway token usage falls back to a complete, untruncated captured JSON response when the gateway input or output count is zero or missing. Supported shapes are Workers AI result.usage.input_tokens/output_tokens, top-level usage.input_tokens/output_tokens, and Chat Completions usage.prompt_tokens/completion_tokens. Each positive gateway count stays authoritative; request logs, GenAI spans and token counters/histograms share the resolved values. A missing or zero total is recomputed only when both counts are known and their sum fits in a signed 64-bit integer. Negative, fractional, non-numeric and overflowing body counts are rejected. Non-JSON, unavailable and truncated bodies supply no fallback. This requires ai_gateway.capture_bodies; no extra API reads are made and capture limits stay in force. Usage source is absent when no body count is used. Costs are not inferred from token counts. Previously committed rows are not reprocessed; compare post-deployment source windows after checkpoint lag has recovered.

cloudflare.ai_gateway.log_coverage.gap comes from the separate aigateway.coverage collector, which is off by default. REST gateway logs stay the primary AI Gateway source; requests sent with log collection off, or dropped by gateway log limits or retention, never appear there, while aiGatewayRequestsAdaptiveGroups still counts them. Each commit compares one closed, aligned five-minute window ending at least 10 minutes before now, held back past the measured 139-365 s Groups ingestion lag, and reports one value per configured gateway: positive means Groups counted requests the REST log lacks, zero means the sources agree, and negative means Groups is behind REST. The Groups selection is count and dimensions.gateway, checked against the dataset's availableFields; a window older than the dataset's notOlderThan is skipped as a retention gap. The REST count pages the gateway log list and counts distinct log IDs. A failed commit retries the same window, and the gauge value for a window never accumulates. The collector polls every five minutes and commits five-minute windows whatever interval and max_window say, so each steady-state poll commits and exports one window; a poll that lands before the next window closes does nothing. During catch-up after an outage or at first start, several windows can commit before one metric export, so the exported gauge carries the newest committed window. An explicit collection range refuses any window that ends inside the 10-minute holdback. It also refuses a range spanning more than one closed five-minute window: the collector always registers with a five-minute max_window, so only an explicit -since/-before range (not the steady-state poll) can ask for more, and exporting just the first window while reporting success would silently hide the rest of the requested range. Request one five-minute window per call instead. Enable it in YAML with enabled, interval, initial_lookback and max_window under collectors.aigateway.coverage, or use environment overrides such as CF2OTEL_COLLECTORS__AIGATEWAY_COVERAGE__ENABLED=true; configuration validation still requires a positive interval and max_window.

The retired AI Gateway dashboard's Data boundaries panel was static provenance guidance; Gateway metadata exceptions was a row grouping failed-request and DLP tables, not a separate API field. The AI Gateway Logs API inventory sampled on 2026-09-26 found no data-boundary or exception fields in 50 log-detail rows. Of that sample, 24 rows had a non-null dlp_action (FLAG), each with one dlp_profiles finding checking either the request (23) or the response (1); dlp_action maps to flagged (FLAG), blocked (BLOCK) or other (any other non-empty value), and a request with an action but no findings still counts once on cloudflare.ai_gateway.dlp.requests with direction other.

Attributes

GroupKeys
Resource and commonservice.name, service.version, service.instance.id, event_name, cf2otel.collector.name, cf2otel.status_class, cf2otel.api.method
Access app and decisioncloudflare.access.app, cloudflare.access.app.id, cloudflare.access.app.type, cloudflare.access.connection, cloudflare.access.host, cloudflare.access.path, cloudflare.access.action, cloudflare.access.allowed, cloudflare.access.country, cloudflare.access.login_type, cloudflare.access.identity_provider, cloudflare.access.service_token
Access identitycloudflare.access.user.email, cloudflare.access.user.id, cloudflare.access.user.ip_address, cloudflare.access.identity.inferred, cloudflare.access.identity.login_ray_id, cloudflare.access.ray_id
Access seatscloudflare.access.seat.type (string enum access, gateway); no user, email, IP, device or account identity attributes.
Access SCIMcloudflare.access.scim.resource_type, cloudflare.access.scim.method, cloudflare.access.scim.status, cloudflare.access.scim.idp_id, cloudflare.access.scim.resource_id, cloudflare.access.scim.user_email
HTTPcloudflare.http.host, cloudflare.http.method, cloudflare.http.path, cloudflare.http.query, cloudflare.http.status_code, cloudflare.http.origin_status_code, cloudflare.http.client_ip, cloudflare.http.user_agent, cloudflare.http.ray_id, cloudflare.http.zone, cloudflare.http.cache_status, cloudflare.http.security_action, cloudflare.http.colo
AI Gateway usage sourcecloudflare.ai_gateway.usage_source: string response_body on request logs and GenAI spans when at least one zero or missing gateway token count is filled from a captured response. Log/span only, never a metric dimension.
AI Gateway contentcloudflare.ai_gateway.content.side, cloudflare.ai_gateway.content.length
AI Gateway non-JSON bodiescloudflare.ai_gateway.request.body_non_json, cloudflare.ai_gateway.response.body_non_json: string "true" on the request log and span when that fetched body is not JSON. No content is exported from that side. cloudflare.ai_gateway.body.side is the counter dimension (request or response).
AI Gateway DLPcloudflare.ai_gateway.dlp.action, cloudflare.ai_gateway.dlp.direction are also bounded metric dimensions on cloudflare.ai_gateway.dlp.requests; cloudflare.ai_gateway.dlp.policy.id and cloudflare.ai_gateway.dlp.profile.id are log and span attributes, never metric dimensions.
Auditcloudflare.audit.* attributes are listed individually below; actor email and IP are log only.
Firewallcloudflare.firewall.* attributes are listed individually below; IP, path, query, user agent and ray are log only.
DNScloudflare.dns.* attributes are listed individually below; query name, IPs and cloudflare.dns.colo are log only.
Gateway DNScloudflare.gateway.dns.query.type, cloudflare.gateway.dns.decision, cloudflare.gateway.dns.country; only bounded metric dimensions.
Platform resource namescloudflare.workers.script_name, cloudflare.r2.bucket_name, cloudflare.r2.catalog.namespace_name, cloudflare.r2sql.bucket_name; bounded names only.
Platform resolved namescloudflare.d1.database_name, cloudflare.kv.namespace_name, cloudflare.queues.queue_name, cloudflare.durableobjects.namespace_name; string names, never source IDs.
R2 operationscloudflare.r2.action_type; string action type, selected only when advertised.
RUMcloudflare.rum.country, cloudflare.rum.device_type, cloudflare.rum.site_tag; gauges use device and optional site tag. Web-vitals quantiles that are absent, null or negative emit no point, including when a previous window had a value; genuine zero measurements remain zero.
Window deliverycf2otel.window.* describes retention gaps and commit outcomes.
Pollercf2otel.collector, cf2otel.version, cf2otel.commit, cf2otel.export.signal, cf2otel.build.version, cf2otel.build.commit

D1/KV/Queue/Durable Objects base metrics resolve IDs through read-only account list endpoints. Successful and failed name lookups are cached for one hour, shared within each domain. Requests start at 50 rows per page and follow server-capped page sizes, up to 100 pages and 5000 rows. Only a complete, consistent list is published; a later-page or refresh failure replaces any expired mapping with a failed state, yielding other for one hour rather than retaining stale names indefinitely. Blank, invalid UTF-8, over-128-character, reserved other, unknown and ambiguous names yield other; IDs never become a fallback label. Optional unavailable grouping fields yield a safe remainder; required Queue statistics fields remain mandatory.

Each affected base metric admits 49 normal complete attribute sets for the collector lifetime plus one reserved other set (50 total). Admission stays sticky across windows, bounding cumulative SDK series growth until restart. R2 operations count the bucket/action pair, so different actions on one bucket remain distinct until capped; the canonical remainder sets every present resource/action dimension to other and conserves counter sums (gauge remainder is MAX). The existing total platform per-window cap defaults to 500 and applies deterministic full-attribute ordering when truncation is necessary. Existing metric names, units and depth quantile selections are unchanged; percentiles are never averaged. Operator-defined resource names may be sensitive: review them before export. Dashboard panels and live/canary entitlement proof are separate root-owned work.

Only bounded attributes should be used to group metrics. cloudflare.access.identity.inferred=true means a time, host and IP correlation, not a Cloudflare-provided identity on the HTTP event.

Declared name inventory

This exhaustive inventory is keyed to the internal/semconv declarations. It includes attributes that may appear only when the source API returns their fields or body capture is enabled.

KindName
Eventcf2otel.process.log
Eventcf2otel.window.gap
Eventcloudflare.access.login
Eventcloudflare.access.scim_update
Eventcloudflare.ai_gateway.request
Eventcloudflare.audit.event
Eventcloudflare.dns.query
Eventcloudflare.firewall.event
Eventcloudflare.http.request
Eventgen_ai.client.inference.operation.details
Metriccf2otel.api.duration
Metriccf2otel.api.limiter_wait
Metriccf2otel.api.requests
Metriccf2otel.api.envelope_errors
Metriccf2otel.api.retries
Metriccf2otel.build.info
Metriccf2otel.scrape.interval
Metriccf2otel.scrape.elapsed
Metriccf2otel.checkpoint.backlog
Metriccf2otel.checkpoint.age
Metriccf2otel.export.errors
Metriccf2otel.export.success
Metriccf2otel.identity.outcomes
Metriccf2otel.process.start_time
Attributecf2otel.identity.outcome
Attributecf2otel.error.class
Metriccf2otel.scrape.duration
Metriccf2otel.scrape.errors
Metriccf2otel.scrape.last_success_timestamp
Metriccf2otel.scrape.success
Metriccf2otel.zones.discovered
Metriccf2otel.zones.filtered
Metriccf2otel.zones.processed
Metriccf2otel.zones.skipped
Attributecf2otel.zone.reason
Metriccf2otel.window.commit_failures
Metriccf2otel.window.catchup_windows
Metriccf2otel.window.gap
Metriccloudflare.access.apps
Metriccloudflare.access.identity_logins
Metriccloudflare.access.logins
Metriccloudflare.access.requests
Metriccloudflare.access.users
Metriccloudflare.access.seats
Metriccloudflare.ai_gateway.cache_hits
Metriccloudflare.ai_gateway.cost
Metriccloudflare.ai_gateway.dlp.requests
Metriccloudflare.ai_gateway.errors
Metriccloudflare.ai_gateway.body_non_json
Metriccloudflare.ai_gateway.log_coverage.gap
Metriccloudflare.ai_gateway.requests
Metriccloudflare.audit.events
Metriccloudflare.dns.queries
Metriccloudflare.email.routing.events
Metriccloudflare.email.sending.events
Metriccloudflare.gateway.dns.queries
Metriccloudflare.firewall.events
Metriccloudflare.http.origin.duration
Metriccloudflare.http.requests
Metriccloudflare.rum.page_views
Metriccloudflare.rum.sessions
Metriccloudflare.rum.lcp.p75
Metriccloudflare.rum.inp.p75
Metriccloudflare.rum.fid.p75
Metriccloudflare.rum.fcp.p75
Metriccloudflare.rum.ttfb.p75
Metriccloudflare.rum.cls.p75
Metricgen_ai.client.inference.operation.input_tokens
Metricgen_ai.client.inference.operation.output_tokens
Metricgen_ai.client.inference.usage.cache_read.input_tokens
Metricgen_ai.client.inference.usage.input_tokens
Metricgen_ai.client.inference.usage.output_tokens
Metricgen_ai.client.inference.usage.reasoning.output_tokens
Metricgen_ai.client.operation.duration
Metriccloudflare.d1.queries
Metriccloudflare.d1.read_queries
Metriccloudflare.d1.storage.max_database_bytes
Metriccloudflare.d1.write_queries
Metriccloudflare.durableobjects.requests
Metriccloudflare.durableobjects.sql_storage.max_namespace_bytes
Metriccloudflare.durableobjects.subrequests
Metriccloudflare.durableobjects.subrequests.request_body.bytes
Metriccloudflare.kv.requests
Metriccloudflare.kv.storage.max_namespace_bytes
Metriccloudflare.kv.storage.max_namespace_keys
Metriccloudflare.logpush.records
Metriccloudflare.logpush.uploads
Metriccloudflare.queues.backlog.max_queue_avg_bytes
Metriccloudflare.queues.backlog.max_queue_avg_messages
Metriccloudflare.queues.consumer.max_queue_avg_concurrency
Metriccloudflare.queues.delayed_backlog.max_queue_avg_messages
Metriccloudflare.queues.message.billable_operations
Metriccloudflare.queues.message.operations
Metriccloudflare.r2.bandwidth.download.bytes
Metriccloudflare.r2.bandwidth.upload.bytes
Metriccloudflare.r2.catalog.data.operations
Metriccloudflare.r2.catalog.maintenance.jobs
Metriccloudflare.r2.requests
Metriccloudflare.r2.storage.objects
Metriccloudflare.r2.storage.payload.bytes
Metriccloudflare.r2sql.queries
Metriccloudflare.turnstile.events
Metriccloudflare.workers.requests
Attributecloudflare.d1.database_name
Attributecloudflare.kv.namespace_name
Attributecloudflare.queues.queue_name
Attributecloudflare.durableobjects.namespace_name
Attributecloudflare.r2.action_type
Attributecloudflare.r2.bucket_name
Attributecloudflare.r2.catalog.namespace_name
Attributecloudflare.r2sql.bucket_name
Attributecloudflare.workers.script_name
Attributecf2otel.api.method
Attributecf2otel.build.commit
Attributecf2otel.build.version
Attributecf2otel.collector
Attributecf2otel.collector.name
Attributecf2otel.commit
Attributecf2otel.export.signal
Attributecf2otel.status_class
Attributecf2otel.version
Attributecf2otel.window.floor
Attributecf2otel.window.from
Attributecf2otel.window.gap_seconds
Attributecloudflare.access.action
Attributecloudflare.access.allowed
Attributecloudflare.access.app
Attributecloudflare.access.app.id
Attributecloudflare.access.app.type
Attributecloudflare.access.connection
Attributecloudflare.access.country
Attributecloudflare.access.host
Attributecloudflare.access.identity.inferred
Attributecloudflare.access.identity.login_ray_id
Attributecloudflare.access.identity_provider
Attributecloudflare.access.login_type
Attributecloudflare.access.path
Attributecloudflare.access.ray_id
Attributecloudflare.access.seat.type
Attributecloudflare.access.scim.idp_id
Attributecloudflare.access.scim.method
Attributecloudflare.access.scim.resource_id
Attributecloudflare.access.scim.resource_type
Attributecloudflare.access.scim.status
Attributecloudflare.access.scim.user_email
Attributecloudflare.access.service_token
Attributecloudflare.access.user.email
Attributecloudflare.access.user.id
Attributecloudflare.access.user.ip_address
Attributecloudflare.ai_gateway.authentication.present
Attributecloudflare.ai_gateway.byok
Attributecloudflare.ai_gateway.cached
Attributecloudflare.ai_gateway.content.length
Attributecloudflare.ai_gateway.content.side
Attributecloudflare.ai_gateway.cost
Attributecloudflare.ai_gateway.created_at
Attributecloudflare.ai_gateway.custom_cost
Attributecloudflare.ai_gateway.dlp.action
Attributecloudflare.ai_gateway.dlp.direction
Attributecloudflare.ai_gateway.dlp.policy.id
Attributecloudflare.ai_gateway.dlp.profile.id
Attributecloudflare.ai_gateway.dlp.profiles
Attributecloudflare.ai_gateway.duration_ms
Attributecloudflare.ai_gateway.event.id
Attributecloudflare.ai_gateway.feedback
Attributecloudflare.ai_gateway.gateway.name
Attributecloudflare.ai_gateway.guardrails
Attributecloudflare.ai_gateway.location.colo
Attributecloudflare.ai_gateway.location.region
Attributecloudflare.ai_gateway.log.id
Attributecloudflare.ai_gateway.metadata
Attributecloudflare.ai_gateway.model.type
Attributecloudflare.ai_gateway.operation
Attributecloudflare.ai_gateway.path
Attributecloudflare.ai_gateway.prompts
Attributecloudflare.ai_gateway.provider
Attributecloudflare.ai_gateway.request.body
Attributecloudflare.ai_gateway.request.body_truncated
Attributecloudflare.ai_gateway.request.body_unavailable
Attributecloudflare.ai_gateway.request.body_non_json
Attributecloudflare.ai_gateway.body.side
Attributecloudflare.ai_gateway.request.content_type
Attributecloudflare.ai_gateway.request.head
Attributecloudflare.ai_gateway.request.head_complete
Attributecloudflare.ai_gateway.request.size
Attributecloudflare.ai_gateway.request.type
Attributecloudflare.ai_gateway.response.body
Attributecloudflare.ai_gateway.response.body_truncated
Attributecloudflare.ai_gateway.response.body_unavailable
Attributecloudflare.ai_gateway.response.body_non_json
Attributecloudflare.ai_gateway.response.head
Attributecloudflare.ai_gateway.response.head_complete
Attributecloudflare.ai_gateway.response.size
Attributecloudflare.ai_gateway.score
Attributecloudflare.ai_gateway.status_code
Attributecloudflare.ai_gateway.step
Attributecloudflare.ai_gateway.success
Attributecloudflare.ai_gateway.timings.latency_ms
Attributecloudflare.ai_gateway.timings.total_ms
Attributecloudflare.ai_gateway.usage.total_tokens
Attributecloudflare.ai_gateway.user_agent
Attributecloudflare.ai_gateway.wholesale
Attributecloudflare.audit.action.description
Attributecloudflare.audit.action.result
Attributecloudflare.audit.action.time
Attributecloudflare.audit.action.type
Attributecloudflare.audit.actor.email
Attributecloudflare.audit.actor.id
Attributecloudflare.audit.actor.ip
Attributecloudflare.audit.actor.token.id
Attributecloudflare.audit.actor.token.name
Attributecloudflare.audit.actor.type
Attributecloudflare.audit.id
Attributecloudflare.audit.raw.method
Attributecloudflare.audit.raw.ray_id
Attributecloudflare.audit.raw.status_code
Attributecloudflare.audit.raw.uri
Attributecloudflare.audit.raw.user_agent
Attributecloudflare.audit.resource.id
Attributecloudflare.audit.resource.product
Attributecloudflare.audit.resource.type
Attributecloudflare.dns.zone
Attributecloudflare.dns.query.name
Attributecloudflare.dns.query.type
Attributecloudflare.dns.response.code
Attributecloudflare.dns.response.cached
Attributecloudflare.dns.response.stale
Attributecloudflare.dns.protocol
Attributecloudflare.dns.colo
Attributecloudflare.dns.source.ip
Attributecloudflare.dns.destination.ip
Attributecloudflare.dns.upstream.ip
Attributecloudflare.dns.ip.version
Attributecloudflare.dns.sample.interval
Attributecloudflare.dns.query.size
Attributecloudflare.dns.response.size
Attributecloudflare.firewall.action
Attributecloudflare.firewall.bot_score_bucket
Attributecloudflare.firewall.bot_score_source
Attributecloudflare.firewall.client.asn
Attributecloudflare.firewall.client.asn_description
Attributecloudflare.firewall.client.country
Attributecloudflare.firewall.client.ip
Attributecloudflare.firewall.colo
Attributecloudflare.firewall.edge_status_code
Attributecloudflare.firewall.host
Attributecloudflare.firewall.kind
Attributecloudflare.firewall.method
Attributecloudflare.firewall.origin_status_code
Attributecloudflare.firewall.path
Attributecloudflare.firewall.protocol
Attributecloudflare.firewall.query
Attributecloudflare.firewall.ray_id
Attributecloudflare.firewall.rule_id
Attributecloudflare.firewall.rule_description
Attributecloudflare.firewall.ruleset_id
Attributecloudflare.firewall.source
Attributecloudflare.firewall.user_agent
Attributecloudflare.firewall.waf_attack_score_class
Attributecloudflare.firewall.zone
Attributecloudflare.http.cache_status
Attributecloudflare.http.client_ip
Attributecloudflare.http.colo
Attributecloudflare.http.host
Attributecloudflare.http.method
Attributecloudflare.http.origin_status_code
Attributecloudflare.http.path
Attributecloudflare.http.query
Attributecloudflare.http.ray_id
Attributecloudflare.http.security_action
Attributecloudflare.http.status_code
Attributecloudflare.http.user_agent
Attributecloudflare.http.zone
Attributecloudflare.gateway.dns.query.type
Attributecloudflare.gateway.dns.decision
Attributecloudflare.gateway.dns.country
Attributecloudflare.rum.site_tag
Attributecloudflare.rum.device_type
Attributecloudflare.rum.country
Attributeerror.type
Attributeevent_name
Attributegen_ai.input.messages
Attributegen_ai.operation.name
Attributegen_ai.output.messages
Attributegen_ai.provider.name
Attributegen_ai.request.model: AI Gateway model identifier with the provider/ prefix removed; unprefixed identifiers and @ model namespaces are preserved. Empty values, empty path segments, null-like placeholders and non-identifier strings (such as prose, JSON or URLs) map to unknown. Identifiers may contain ASCII letters, digits, -, _, ., :, @ and namespace / separators; validation is syntactic, not a model-catalog lookup. The same normalized value is used in logs, spans (including their names), and model-level metrics.
Attributegen_ai.usage.cache_read.input_tokens
Attributegen_ai.usage.cost
Attributegen_ai.usage.input_tokens
Attributegen_ai.usage.output_tokens
Attributegen_ai.usage.reasoning.output_tokens
Attributeoutcome
Attributeservice.instance.id
Attributeservice.name
Attributeservice.version

Loop 14 attribute seams

AttributeMeaning
cf2otel.identity.outcomeIdentity inference outcome: matched, unmatched or ambiguous. (CFO-0058)
cloudflare.statisticStatistic: avg, p50, p75, p95, p99 or p999. (CFO-0046.04 / CFO-0047.01)
cloudflare.workers.statusInvocation status as returned. (CFO-0047.01)
cf2otel.instrumentOverflowing instrument name. (CFO-0045)
cloudflare.http.client.countryUppercase ISO 3166-1 alpha-2 country. (CFO-0046.02)
cloudflare.http.protocolHTTP protocol as returned, e.g. HTTP/2. (CFO-0046.02)
cloudflare.http.tls.protocolTLS protocol as returned, e.g. TLSv1.3 or none. (CFO-0046.02)
cloudflare.http.content_typeEdge response content type name. (CFO-0046.02)
cloudflare.certificate.zoneCertificate pack zone name. (CFO-0050.01)
cloudflare.certificate.pack_idCertificate pack pack_id. (CFO-0050.01)
cloudflare.certificate.typeCertificate pack type. (CFO-0050.01)
cloudflare.certificate.authorityCertificate pack authority. (CFO-0050.01)
cloudflare.certificate.statusCertificate pack status. (CFO-0050.01)
cloudflare.tunnel.idTunnel id. (CFO-0048.01)
cloudflare.tunnel.nameTunnel name. (CFO-0048.01)
cloudflare.tunnel.statusTunnel status. (CFO-0048.01)
cloudflare.tunnel.previous_statusTunnel previous_status. (CFO-0048.01)
cloudflare.tunnel.coloTunnel colo. (CFO-0048.01)
cloudflare.tunnel.connector.versionTunnel connector.version. (CFO-0048.01)

Collector scrape error classes

Registration seeds cf2otel.scrape.errors with one zero-valued point per registered, enabled collector, using cf2otel.error.class="other". This makes never-failing collectors visible without recording a failure. Window collectors also receive a zero-valued cf2otel.window.commit_failures point with only cf2otel.collector; actual commit failures continue to carry their existing signal and retry/dropped outcome dimensions. Disabled collectors get no seed, and disabling periodic self-observability snapshots does not disable these registration points. Dry-run does not export or persist them.

cf2otel.scrape.errors remains a monotonic counter with unit 1: each failed collector attempt adds one, grouped by cf2otel.collector and the bounded cf2otel.error.class attribute. Successful attempts do not add an error. No raw error message, upstream field name, response body or HTTP code becomes an attribute.

AttributeValues
cf2otel.error.classrate_limited, auth, unentitled, timeout, schema, other

Classification follows typed errors through wrappers. Explicit typed entitlement errors take precedence over HTTP status: unavailable GraphQL fields or disabled datasets are unentitled. HTTP 429 is rate_limited; HTTP 401/403 is auth unless a typed entitlement error is present. Context deadline exhaustion and network timeout errors are timeout. GraphQL field-limit errors and JSON syntax or type errors are schema. Retention gaps, saturated windows, cancellation, other HTTP failures and unknown errors are other; message text is never used to infer a class. Classification observes failures without changing retries, permission handling, checkpoint decisions or collector scheduling.

The full classification above applies to collector scrape errors, not export errors or scrape duration/success metrics. Physical-request metrics use the transport-only subset documented above. Existing aggregate queries can continue to sum scrape errors across classes. This is the code/documentation portion of CFO-0051.03 (classify collector errors); the dashboard panel is delivered separately.

Opt-in HTTP colo, ASN and safe error routes

NameKind / unitAttributes
cloudflare.http.requests.by_coloCounter / {request}cloudflare.http.zone, cloudflare.http.colo, remainder.
cloudflare.http.requests.by_asnCounter / {request}Zone, string ASN, string ASN description, remainder. Both ASN fields must be advertised; live-verified on the eligible HTTP Groups zone, not universally available.
cloudflare.http.errors.by_routeCounter / {request}Zone, configured safe route name, status class, remainder. Counts only 4xx/5xx groups; paths are internal lookup inputs, never attributes.
AttributeString value contract
cloudflare.http.client.asnAdvertised source ASN string, without numeric coercion; other in the remainder.
cloudflare.http.client.asn_descriptionAdvertised source organization-description string; other in the remainder.
cloudflare.http.route.nameValidated configured safe name; other for unmatched and overflow counts. Never a raw or normalized path.
cloudflare.http.status_class4xx, 5xx; other in the remainder.
cloudflare.http.breakdown.remainderfalse for normal tuples; true for the single all-other tuple. A real source colo/ASN named other remains distinct via false.

All three toggles are absent by default. Per-feature/zone lexical caps conserve counts in one remainder, and every point counts against the existing complete-window HTTP cap. An optional exact host allowlist filters only these features and adds no host label. See configuration for limits, normalizer behavior and failure semantics. Dashboard delivery is a separate signal batch.

Load balancer provider health flag

SignalTypeUnitAttributes
cloudflare.loadbalancers.pool.healthGauge1cloudflare.loadbalancers.pool.name

The opt-in loadbalancers.health snapshot reads only the documented direct optional result.pop_health.healthy property of the pool health method. This is an unattributed provider-reported health flag, not regional aggregate pool availability: true maps to 1, false to 0, absent/null is unknown and omitted. No region, origin health, origin RTT, weights or rule totals are inferred. The current documented RTT example has an explicit ms suffix, but stable regional and origin attribution is still undocumented and remains unimplemented.

Configured pool names are the only labels, bounded to 128 UTF-8 bytes with no controls. Internal pool IDs are request-only; no identifier/address fallback. The existing platform series cap reserves one other slot and sticky named admission until restart. other is the minimum of known flags among excluded pools (any observed unhealthy flag yields 0), excluding unknowns; it is not a complete fleet health guarantee. Failures and unknown flags can leave coverage incomplete. Snapshots expire after three poll intervals. A valid empty catalog clears them; a valid subset atomically replaces them, omitting unknown and failed pools. All failed reads retain original expiry. An all-unknown valid response clears prior known values and returns an unknown-coverage error, never a healthy classification.

The pool catalog is live-probed by the drift canary and allows empty accounts. Health detail is explicitly documented_only, fixture-only and unprobed because root preparation observed no live pools. Populated runtime health and regional/origin joins remain unverified. The original regional/origin health and RTT acceptance criterion remains incomplete; the request-count addition below does not waive it.

Load balancer pool request counts

SignalTypeUnitAttributes
cloudflare.loadbalancers.pool.requestsExpiring snapshot gauge{request}cloudflare.loadbalancers.pool.name

The existing disabled-by-default loadbalancers.health toggle also collects documented count grouped by dimensions.selectedPoolName from zone-scoped loadBalancingRequestsAdaptiveGroups. Requests mean uncached load-balancer resolutions, not all HTTP requests. No raw Adaptive row counting or sample-interval multiplication is used. The gauge represents the trailing configured polling interval, with half-open [from,to) bounds rounded out to whole source seconds. It replaces, rather than accumulates, overlapping polls; use the value directly, never rate, increase, or a sum over successive snapshots. This is a polling snapshot, not a checkpointed backfill counter. Late-arriving data and polling outages may leave traffic unobserved.

The collector lists pools first. An empty account makes only the pool-list request, clears prior snapshots and makes no zone, health-detail or GraphQL requests. With pools, only zones belonging to the configured account (and existing cloudflare.zones allowlist, if set) are queried. Selections use settings.availableFields; an absent, disabled or explicitly unentitled dataset, or either missing required field, is a traffic no-op with no fabricated zero. Auth, transport, malformed settings/rows, saturation and unusable duration/retention/field/page limits remain errors, with no partial traffic publication or refresh of prior snapshot expiry. One strict singleton batch per eligible zone prevents silent field renegotiation from losing the pool grouping. The canary contract checks these two advertised fields, permits absent/disabled plans, and is proved only by local fake-upstream fixtures; no live dataset proof is claimed.

Public configured pool names are the only labels: no zone/account/pool ID, host, origin address or region is emitted. Names use the same 128-byte UTF-8/no-controls validation. Health takes priority within the existing combined platform series cap; remaining traffic slots admit pool names lexically, reserving one other slot. Traffic other is the sum of overflow counts, a literal pool named other, and historical names unresolved in the current catalog, never the health flag's minimum. If health exhausts the cap, traffic points are omitted. Counts from eligible zones are summed by pool; unentitled zones provide no contribution, so these are not necessarily complete account totals. Empty/denied valid traffic clears prior request counts. Both snapshots expire after three configured polling intervals. Regional/origin health and origin RTT remain explicitly unimplemented.

Completed poll diagnostics

cf2otel.poll.completed is one structured process-pipeline log per scheduler run, including successful, failed and shutdown-canceled runs. cf2otel.poll.outcome is success, error or canceled; cf2otel.collector is a registered collector name. Its JSON body includes wall durations (duration_seconds, collect_seconds, commit_lock_seconds, commit_seconds), committed_windows, committed_logs, committed_spans, and api request totals split into list_requests, detail_requests, body_requests and other_requests. HTTP failures are physical header/transport failures, including handled 404s. http_header_seconds_sum and limiter_wait_seconds_sum sum overlapping requests and must not be added to wall phases. Collection wall time includes body reading and decoding. Committed items are counted only after delivery, metric replay and checkpoint persistence succeed; partial exports, dropped windows and snapshots are not checkpointed item counts. A log count includes span-attached log records. These are telemetry records, not necessarily source rows.

The internal cf2otel.poll span parents operational API spans and correlates the completion log. Imported source spans keep their existing parentage. Operational traces use an independent exporter/processor with the same configured endpoint and resource under the existing provider lifecycle. Their export outcome uses cf2otel.export.signal=operational_traces, outside source-commit failure tracking. No SDK global provider, sampling or destination changes are introduced.

MetricUnitDescription
cf2otel.poll.phase.durationsWall time by collector and cf2otel.poll.phase (collect, commit_lock, commit), with scrape-duration buckets through 7200 seconds.
cf2otel.poll.committed.items{item}Checkpointed items by collector and cf2otel.export.signal (windows, logs, spans).
KindName
Eventcf2otel.poll.completed
Spancf2otel.poll
Metriccf2otel.poll.phase.duration
Metriccf2otel.poll.committed.items
Attributecf2otel.poll.outcome
Attributecf2otel.poll.phase