diff --git a/develop-docs/sdk/telemetry/logs.mdx b/develop-docs/sdk/telemetry/logs.mdx index 6bb46e3ef9f72..0a7b93bcffd68 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-02-06 + summary: Added sentry.timestamp.sequence default 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 @@ -153,6 +156,7 @@ SDKs **MUST** attach the following attributes to every log: | `sentry.sdk.name` | 1.0.0 | The name of the SDK that sent the log. | | `sentry.sdk.version` | 1.0.0 | The version of the SDK that sent the log. | | `sentry.replay_id` | 1.8.0 | The replay ID of the active replay when the log was collected. **MUST NOT** be set if no replay is active. | +| `sentry.timestamp.sequence` | 1.16.0 | A monotonically incrementing integer counter used to determine correct ordering of logs when timestamps are identical. **MUST** be sent on runtimes with frozen or low-precision timers, **MAY** be omitted otherwise. See [Log Ordering](#log-ordering). | For parameterized logs, SDKs **MUST** also attach: @@ -290,6 +294,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 number **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 +586,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 +612,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 +638,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 +665,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 +693,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 +723,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..9062ef17032e1 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-02-06 + summary: Added sentry.timestamp.sequence default 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 @@ -114,6 +117,7 @@ SDKs **MUST** attach the following attributes to every metric by default: 2. `sentry.release` — the release set in the SDK, if defined. 3. `sentry.sdk.name` — the name of the SDK that sent the metric. 4. `sentry.sdk.version` — the version of the SDK that sent the metric. +5. `sentry.timestamp.sequence` — a monotonically incrementing integer counter used to determine correct ordering of metrics when timestamps are identical. **MUST** be sent on runtimes with frozen or low-precision timers, **MAY** be omitted otherwise. See [Metric Ordering](#metric-ordering). SDKs **SHOULD** minimize the number of default attributes. Metrics cardinality can explode quickly with too many attributes. New default attributes **SHOULD** only be added after significant feedback from users and discussion internally with the SDK and ingest teams. @@ -187,6 +191,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 number **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 +570,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 +586,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 +602,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 +619,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 +634,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" } } } ]