diff --git a/develop-docs/sdk/telemetry/logs.mdx b/develop-docs/sdk/telemetry/logs.mdx index 6bb46e3ef9f72..94eeccf407b23 100644 --- a/develop-docs/sdk/telemetry/logs.mdx +++ b/develop-docs/sdk/telemetry/logs.mdx @@ -2,7 +2,7 @@ title: Logs description: Structured logging protocol with severity levels, trace context, and batched envelope delivery. spec_id: sdk/telemetry/logs -spec_version: 1.15.0 +spec_version: 1.16.0 spec_status: stable spec_depends_on: - id: sdk/foundations/transport/envelopes @@ -10,6 +10,9 @@ spec_depends_on: - id: sdk/foundations/state-management/scopes/attributes version: ">=1.0.0" spec_changelog: + - version: 1.16.0 + date: 2026-03-04 + summary: Add sentry.timestamp.sequence attribute for deterministic log ordering - version: 1.15.0 date: 2026-02-03 summary: Clarified 100 logs per envelope hard limit, SDKs MAY use lower buffer limit @@ -290,6 +293,25 @@ Logs **SHOULD** be associated with replays. If a log is recorded during an activ +### Log Ordering + + + +Some runtimes (notably Cloudflare Workers) freeze timer APIs (`Date.now()`, `performance.now()`) during synchronous execution, causing multiple logs to share identical timestamps. SDKs that target runtimes where timestamps may be frozen or lack sub-millisecond precision **MUST** attach a `sentry.timestamp.sequence` integer attribute to every log. SDKs that only target runtimes with reliable sub-millisecond timestamps **MAY** omit it. + +When sent, the sequence integer **MUST**: +- Start at `0` when the SDK initializes. +- Increment by `1` for each log that is captured. +- Reset to `0` when: + - The SDK is re-initialized. + - The current log's integer millisecond differs from the previous log's integer millisecond (i.e., `floor(timestamp_seconds * 1000)` changes). + +The sequence provides deterministic ordering within a single SDK instance. It does not guarantee ordering across independent processes or workers, which have separate counters. The reset behavior ensures the sequence only increments for consecutive logs that share the same timestamp. + + + +### Debug Mode + ### Debug Mode @@ -563,7 +585,8 @@ A complete `log` envelope with six log entries at different severity levels: }, "sentry.message.parameter.0": { "value": 120, "type": "integer" }, "sentry.message.parameter.1": { "value": 85, "type": "integer" }, - "sentry.message.parameter.2": { "value": 60, "type": "integer" } + "sentry.message.parameter.2": { "value": 60, "type": "integer" }, + "sentry.timestamp.sequence": { "value": 0, "type": "integer" } } }, { @@ -588,7 +611,8 @@ A complete `log` envelope with six log entries at different severity levels: "value": "ProductCard", "type": "string" }, - "sentry.message.parameter.1": { "value": 3, "type": "integer" } + "sentry.message.parameter.1": { "value": 3, "type": "integer" }, + "sentry.timestamp.sequence": { "value": 1, "type": "integer" } } }, { @@ -613,7 +637,8 @@ A complete `log` envelope with six log entries at different severity levels: "value": "checkout_form", "type": "string" }, - "sentry.message.parameter.1": { "value": 8, "type": "integer" } + "sentry.message.parameter.1": { "value": 8, "type": "integer" }, + "sentry.timestamp.sequence": { "value": 2, "type": "integer" } } }, { @@ -639,7 +664,8 @@ A complete `log` envelope with six log entries at different severity levels: "type": "string" }, "sentry.message.parameter.1": { "value": 2500, "type": "integer" }, - "sentry.message.parameter.2": { "value": 1000, "type": "integer" } + "sentry.message.parameter.2": { "value": 1000, "type": "integer" }, + "sentry.timestamp.sequence": { "value": 3, "type": "integer" } } }, { @@ -666,7 +692,8 @@ A complete `log` envelope with six log entries at different severity levels: "sentry.message.parameter.0": { "value": "prod_123, prod_456", "type": "string" - } + }, + "sentry.timestamp.sequence": { "value": 4, "type": "integer" } } }, { @@ -695,7 +722,8 @@ A complete `log` envelope with six log entries at different severity levels: "sentry.message.parameter.1": { "value": "UPDATE_CART", "type": "string" - } + }, + "sentry.timestamp.sequence": { "value": 5, "type": "integer" } } } ] diff --git a/develop-docs/sdk/telemetry/metrics.mdx b/develop-docs/sdk/telemetry/metrics.mdx index 30664770f81d3..cd323f8954dbe 100644 --- a/develop-docs/sdk/telemetry/metrics.mdx +++ b/develop-docs/sdk/telemetry/metrics.mdx @@ -2,7 +2,7 @@ title: Metrics description: Counter, gauge, and distribution metrics sent as batched trace_metric envelope items. spec_id: sdk/telemetry/metrics -spec_version: 2.5.0 +spec_version: 2.6.0 spec_status: stable spec_depends_on: - id: sdk/foundations/transport/envelopes @@ -10,6 +10,9 @@ spec_depends_on: - id: sdk/foundations/state-management/scopes/attributes version: ">=1.0.0" spec_changelog: + - version: 2.6.0 + date: 2026-03-04 + summary: Add sentry.timestamp.sequence attribute for deterministic metric ordering - version: 2.5.0 date: 2026-02-12 summary: Clarified sendDefaultPii gating for user attributes — allowed when user manually sets data @@ -187,6 +190,25 @@ Whenever possible, metrics **SHOULD** be linked to replays. If a metric is recor +### Metric Ordering + + + +Some runtimes (notably Cloudflare Workers) freeze timer APIs (`Date.now()`, `performance.now()`) during synchronous execution, causing multiple metrics to share identical timestamps. SDKs that target runtimes where timestamps may be frozen or lack sub-millisecond precision **MUST** attach a `sentry.timestamp.sequence` integer attribute to every metric. SDKs that only target runtimes with reliable sub-millisecond timestamps **MAY** omit it. + +When sent, the sequence integer **MUST**: +- Start at `0` when the SDK initializes. +- Increment by `1` for each metric that is captured. +- Reset to `0` when: + - The SDK is re-initialized. + - The current metric's integer millisecond differs from the previous metric's integer millisecond (i.e., `floor(timestamp_seconds * 1000)` changes). + +The sequence provides deterministic ordering within a single SDK instance. It does not guarantee ordering across independent processes or workers, which have separate counters. The reset behavior ensures the sequence only increments for consecutive metrics that share the same timestamp. + + + +### Data Category and Rate Limiting + ### Data Category and Rate Limiting @@ -547,7 +569,8 @@ SentrySDK.metrics() "sentry.sdk.name": { "value": "sentry.javascript.browser", "type": "string" }, "sentry.sdk.version": { "value": "10.17.0", "type": "string" }, "sentry.environment": { "value": "production", "type": "string" }, - "sentry.release": { "value": "1.0.0", "type": "string" } + "sentry.release": { "value": "1.0.0", "type": "string" }, + "sentry.timestamp.sequence": { "value": 0, "type": "integer" } } }, { @@ -562,7 +585,8 @@ SentrySDK.metrics() "endpoint": { "value": "/api/users", "type": "string" }, "method": { "value": "POST", "type": "string" }, "sentry.sdk.name": { "value": "sentry.javascript.browser", "type": "string" }, - "sentry.sdk.version": { "value": "10.17.0", "type": "string" } + "sentry.sdk.version": { "value": "10.17.0", "type": "string" }, + "sentry.timestamp.sequence": { "value": 1, "type": "integer" } } }, { @@ -577,7 +601,8 @@ SentrySDK.metrics() "cache_name": { "value": "user_sessions", "type": "string" }, "region": { "value": "us-west-1", "type": "string" }, "sentry.sdk.name": { "value": "sentry.javascript.browser", "type": "string" }, - "sentry.sdk.version": { "value": "10.17.0", "type": "string" } + "sentry.sdk.version": { "value": "10.17.0", "type": "string" }, + "sentry.timestamp.sequence": { "value": 0, "type": "integer" } } }, { @@ -593,7 +618,8 @@ SentrySDK.metrics() "table": { "value": "users", "type": "string" }, "sentry.sdk.name": { "value": "sentry.javascript.browser", "type": "string" }, "sentry.sdk.version": { "value": "10.17.0", "type": "string" }, - "sentry.origin": { "value": "auto.db.graphql", "type": "string" } + "sentry.origin": { "value": "auto.db.graphql", "type": "string" }, + "sentry.timestamp.sequence": { "value": 1, "type": "integer" } } }, { @@ -607,7 +633,8 @@ SentrySDK.metrics() "cohort": { "value": "beta", "type": "string" }, "sentry.sdk.name": { "value": "sentry.javascript.browser", "type": "string" }, "sentry.sdk.version": { "value": "10.17.0", "type": "string" }, - "sentry.replay_id": { "value": "36b75d9fa11f45459412a96c41bdf691", "type": "string" } + "sentry.replay_id": { "value": "36b75d9fa11f45459412a96c41bdf691", "type": "string" }, + "sentry.timestamp.sequence": { "value": 0, "type": "integer" } } } ]