diff --git a/develop-docs/sdk/telemetry/logs.mdx b/develop-docs/sdk/telemetry/logs.mdx
index 88bc9e521f2a61..6834d7748305b4 100644
--- a/develop-docs/sdk/telemetry/logs.mdx
+++ b/develop-docs/sdk/telemetry/logs.mdx
@@ -1,434 +1,526 @@
---
title: Logs
+spec_id: sdk/telemetry/logs
+spec_version: 1.15.0
+spec_status: stable
+spec_depends_on:
+ - id: sdk/foundations/data-model/envelopes
+ version: ">=1.0.0"
+ - id: sdk/telemetry/attributes
+ version: ">=1.0.0"
+spec_changelog:
+ - version: 1.15.0
+ date: 2026-02-03
+ summary: Clarified 100 logs per envelope hard limit, SDKs MAY use lower buffer limit
+ - version: 1.14.0
+ date: 2025-12-16
+ summary: User attributes now optional, guarded by sendDefaultPii
+ - version: 1.13.0
+ date: 2025-11-18
+ summary: Added client reports requirement (log_item count, log_byte size)
+ - version: 1.12.0
+ date: 2025-11-10
+ summary: Added buffer hard limit of 1000 queued log events
+ - version: 1.11.0
+ date: 2025-10-30
+ summary: Added span_id as top-level payload field, replaced sentry.trace.parent_span_id attribute
+ - version: 1.10.0
+ date: 2025-10-22
+ summary: Hub/Scope MUST offer same logger methods as static API, Client SHOULD offer generic captureLog
+ - version: 1.9.0
+ date: 2025-10-09
+ summary: Consolidated sentry.origin rules — no origin for manual calls, auto.log.* for libraries, auto.*.* for instrumentation
+ - version: 1.8.0
+ date: 2025-09-10
+ summary: Added sentry.replay_id as default attribute and replay association behavior
+ - version: 1.7.0
+ date: 2025-08-28
+ summary: Added message template constraint — MUST NOT send sentry.message.template without parameters
+ - version: 1.6.0
+ date: 2025-06-10
+ summary: User attributes no longer gated behind sendDefaultPii
+ - version: 1.5.0
+ date: 2025-05-27
+ summary: Added platform-specific default attributes for browser, backend, mobile/desktop/native
+ - version: 1.4.0
+ date: 2025-05-08
+ summary: Added Tracing without Performance as prerequisite for logs
+ - version: 1.3.0
+ date: 2025-05-07
+ summary: Added structured log processing pipeline, removed logsSampleRate init option
+ - version: 1.2.0
+ date: 2025-05-01
+ summary: Refined buffering requirements (100 items or 5 seconds flush)
+ - version: 1.1.0
+ date: 2025-04-24
+ summary: Documented log envelope item structure (items array wrapper)
+ - version: 1.0.0
+ date: 2025-04-22
+ summary: Initial spec — log protocol, severity model, logger API, init options, otel_log format
sidebar_order: 3
---
-This document defines the format used by Sentry to ingest logs, as well as the SDK API and behavior that create and send logs to Sentry.
+
-## Logs Protocol
+
-There are two ways to send logs to Sentry: via the `log` envelope and Sentry Log protocol (preferred), or the `otel_log` envelope and OpenTelemetry Log protocol.
+## Overview
-All SDKs are required to send logs via the `log` envelope and Sentry Log protocol. The `otel_log` envelope and OpenTelemetry Log protocol are just documented for completeness and to provide a reference for SDK authors. See the [Appendix B](#appendix-b-otel_log-envelope-item-payload) for the `otel_log` envelope item payload.
+Logs allow Sentry to ingest structured log data from SDKs. SDKs send log envelopes containing structured log payloads with severity levels, trace context, and arbitrary attributes. Sentry uses this data to provide searchable, correlated log views alongside errors and traces.
-### `log` Envelope Item
+There are two wire protocols: the `log` envelope with the Sentry Log protocol (preferred), and the `otel_log` envelope with the OpenTelemetry Log protocol. All SDKs **MUST** send logs via the `log` envelope and Sentry Log protocol. The `otel_log` format is documented in [Appendix: `otel_log` Format](#otel_log-envelope-item-payload) for completeness.
-The `log` envelope item is an object that contains an array of log payloads encoded as JSON. This allows for multiple log payloads to be sent in a single envelope item. For more details on the `log` envelope item, see the [Log Envelope Item](/sdk/foundations/data-model/envelope-items/#log) documentation. See [Appendix A](#appendix-a-log-envelope-item-payload) for an example `log` envelope.
+Related specs:
+- [Envelopes](/sdk/foundations/data-model/envelopes/) — transport format
+- [Envelope Items](/sdk/foundations/data-model/envelope-items/) — `log` item type constraints
+- [Attributes](/sdk/telemetry/attributes) — attribute type system
+- [Tracing without Performance](/sdk/telemetry/traces/tracing-without-performance) — required for trace context
+- [Trace Origin](/sdk/telemetry/traces/trace-origin/) — origin attribute format
-```json
-{
- "type": "log",
- "item_count": 5,
- "content_type": "application/vnd.sentry.items.log+json"
-}
-{
- "items": [{..log..}, {..log..}, {..log..}, {..log..}, {..log..}]
-}
-```
+---
-### `log` Envelope Item Payload
+## Concepts
-The `log` envelope item payload is a JSON object that represents a Sentry Log.
+### Structured Logging
+
+Logs support parameterized message templates for structured logging. Instead of interpolating values into the message body directly, SDKs send the template and parameters separately. This enables Sentry to group similar log messages and perform efficient searching.
-```json
-{
- "timestamp": 1544719860.0,
- "trace_id": "5b8efff798038103d269b633813fc60c",
- "span_id": "b0e6f15b45c36b12",
- "level": "info",
- "body": "User John has logged in!",
- "attributes": {
- "sentry.message.template": {
- "value": "User %s has logged in!",
- "type": "string"
- },
- "sentry.message.parameter.0": {
- "value": "John",
- "type": "string"
- },
- "sentry.environment": {
- "value": "production",
- "type": "string"
- },
- "sentry.release": {
- "value": "1.0.0",
- "type": "string"
- }
- }
-}
+```
+Template: "User %s has logged in!"
+Parameter 0: "John"
+Body: "User John has logged in!"
```
-It consists of the following fields:
+The SDK sends the interpolated `body`, the `sentry.message.template`, and `sentry.message.parameter.X` attributes.
-`timestamp`
+### Severity Levels
-: **Number, required**. The timestamp of the log in seconds since the Unix epoch.
+Logs use a severity model with six levels (lowest to highest): `trace`, `debug`, `info`, `warn`, `error`, `fatal`. These map exactly to [OpenTelemetry's Severity text field](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitytext).
-`trace_id`
+Each level maps to a numeric severity range following the [OpenTelemetry Severity Number](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber) specification:
-: **String, required**. The trace id of the log. The value should be 16 random bytes encoded as a hex string (32 characters long). The trace id should be grabbed from the current propagation context in the SDK.
+| SeverityNumber range | Range name | Meaning |
+| -------------------- | ---------- | ------- |
+| 1-4 | Trace | A fine-grained debugging event. Typically disabled in default configurations. |
+| 5-8 | Debug | A debugging event. |
+| 9-12 | Info | An informational event. Indicates that an event happened. |
+| 13-16 | Warn | A warning event. Not an error but is likely more important than an informational event. |
+| 17-20 | Error | An error event. Something went wrong. |
+| 21-24 | Fatal | A fatal error such as application or system crash. |
-`span_id`
+SDKs **SHOULD** set the lowest severity number for a given severity level (e.g., `warn` uses severity number `13`).
-: **String, optional**. The span id of the span that was active when the log was collected. The value should be 8 random bytes encoded as a hex string (16 characters long). The span id should be grabbed from the current active span in the SDK.
+### Log Buffering
-`level`
+Logs are buffered before sending. SDKs collect logs into a buffer and flush them as a batch in a single `log` envelope item, rather than sending each log individually. This reduces network overhead and aligns with Relay, which is optimized for up to 100 logs per envelope.
-: **String, required**. The severity level of the log. One of `trace`, `debug`, `info`, `warn`, `error`, `fatal` (in order of lowest to highest).
+---
-`body`
+## Behavior
-: **String, required**. The log body/message.
+### Log Processing Pipeline
-`attributes`
+
-: **Object, optional**. A dictionary of key-value pairs of arbitrary data attached to the log. Attributes must also declare the type of the value. See [Attributes](/sdk/telemetry/attributes) for the supported types and structure.
+Log processing **MUST** follow this order:
-Example:
+1. Capture log via [Public APIs](#logger-module) (e.g. `Sentry.logger.info`) or via [SDK integrations](#sdk-integrations).
+2. Check if logging is enabled via `enableLogs`/`enable_logs` — if not, skip remaining steps.
+3. Pass the log to Hub/Scope, which **MUST** offer the same methods as the static API `Sentry.logger.X`.
+4. Pass the log to the Client via a generic method (e.g., `captureLog(log, scope)`).
+5. Process captured log (attach attributes per [Default Attributes](#default-attributes)).
+6. Run `beforeSendLog`/`before_send_log` to filter or modify the log.
+7. Add log to buffer/batch processor per [Buffering](#buffering).
+8. At flush time, send array of logs to Sentry via `log` envelope, applying rate limiting per [Data Category and Rate Limiting](#data-category-and-rate-limiting).
-```json
-{
- "attributes": {
- "db.namespace": {
- "value": "projects",
- "type": "string"
- },
- "db.response.returned_rows": {
- "value": 123,
- "type": "integer"
- },
- "db_query_processing_time": {
- "value": 123.456,
- "type": "double"
- },
- "is_production_db": {
- "value": false,
- "type": "boolean"
- }
- }
-}
-```
+
-`severity_number`
+An SDK **SHOULD** implement [Tracing without Performance](/sdk/telemetry/traces/tracing-without-performance) before adding support for logs. This is required to ensure logs are associated with traces and that the correct trace context is sent to Sentry.
-: **Integer, optional**. The severity number of the log. See [Log Severity Number](#log-severity-number) for more information. This is inferenced from `level` unless explicitly set.
+
-### Log Severity Level
+
-The log severity level is a string that represents the severity of the log. The Sentry's default log severity level maps exactly to [OpenTelemetry's Severity text field](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitytext) on the OpenTelemetry Logs Spec.
+### Default Attributes
-- `trace`
-- `debug`
-- `info`
-- `warn`
-- `error`
-- `fatal`
+
-### Log Severity Number
+SDKs **MUST** attach the following attributes to every log:
-The log severity number is an integer that represents the severity of the log. The Sentry's default log severity number maps exactly to [OpenTelemetry's Severity number field](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber) on the OpenTelemetry Logs Spec.
+| Attribute | Since | Description |
+|-----------|-------|-------------|
+| `sentry.environment` | 1.0.0 | The environment set in the SDK, if defined. |
+| `sentry.release` | 1.0.0 | The release set in the SDK, if defined. |
+| `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. |
-| SeverityNumber range | Range name | Meaning |
-| -------------------- | ---------- | --------------------------------------------------------------------------------------- |
-| 1-4 | Trace | A fine-grained debugging event. Typically disabled in default configurations. |
-| 5-8 | Debug | A debugging event. |
-| 9-12 | Info | An informational event. Indicates that an event happened. |
-| 13-16 | Warn | A warning event. Not an error but is likely more important than an informational event. |
-| 17-20 | Error | An error event. Something went wrong. |
-| 21-24 | Fatal | A fatal error such as application or system crash. |
+For parameterized logs, SDKs **MUST** also attach:
-Default SDK public API should set the lowest severity number for a given severity level. For example, `warn` severity level logs collected by the SDK API should use the severity number `13`.
+| Attribute | Since | Description |
+|-----------|-------|-------------|
+| `sentry.message.template` | 1.0.0 | The parameterized template string. |
+| `sentry.message.parameter.X` | 1.0.0 | Parameters to the template. `X` is either the positional index (`0`, `1`, etc.) or the parameter name (`item_id`, `user_id`, etc.). |
-## Public API
+If there are no `sentry.message.parameter.X` attributes, SDKs **MUST NOT** attach `sentry.message.template` (since 1.7.0). This reduces duplicate content and simplifies PII processing.
-API wise the SDKs are required to expose logging methods which are to be defined in a `logger` module or namespace. The SDKs should also include some initialization options to configure the behavior of logs in the SDK.
+
-### Initialization Options
+SDKs **SHOULD** minimize default attributes. Logs are charged per byte size. New default attributes **SHOULD** only be added after significant user feedback and discussion with the SDK and ingest teams.
-The SDKs must expose the following configuration options:
+
-- `enableLogs`/`enable_logs`: A boolean flag to control if log envelopes will be generated and sent to Sentry via the Sentry SDK's Logging APIs. If this flag is set to `false`, the SDK should not send logs to Sentry. Defaults to `false`.
+
-- `beforeSendLog`/`before_send_log`: A function that takes a log object and returns a log object. This function is called before sending the log to Sentry. It can be used to modify the log object or to prevent the log from being sent to Sentry. This function is optional.
+### SDK Integration Origin
-While the logs functionality for an SDK is in an experimental state, SDKs should put these configuration options in an experimental namespace to avoid breaking changes.
+
-```js
-Sentry.init({
- _experiments: { enableLogs: true },
-});
-```
+If a log is generated by an SDK integration, the SDK **SHOULD** set the `sentry.origin` attribute per the [Trace Origin](/sdk/telemetry/traces/trace-origin/) documentation.
-### Logger Module
+Since 1.9.0, logs follow these rules:
-At minimum the SDK needs to implement the `Sentry.logger.X` (where `X` is the log level) methods. The log levels are `trace`, `debug`, `info`, `warn`, `error`, and `fatal`, which is specced out by the [protocol below](#log-severity-level).
+1. **User calls Sentry's Logging API directly:** SDKs **MUST NOT** send `sentry.origin`. This intentionally deviates from the Trace Origin spec to minimize log size.
+2. **Captured from a logging library:** Use `auto.log.` format (e.g., `"auto.log.serilog"`).
+3. **Auto-emitted from other instrumented systems:** Use `auto..` format (e.g., `"auto.db.prisma"`).
-- `Sentry.logger.trace`
-- `Sentry.logger.debug`
-- `Sentry.logger.info`
-- `Sentry.logger.warn`
-- `Sentry.logger.error`
-- `Sentry.logger.fatal`
+
-These methods accepts a string template and the parameters to that string template so the SDK can perform structured logging. Optionally these methods take arbitrary attributes, but not all languages can support both passing a parameterized template and attributes in an easy way.
+### User Attributes
-```js
-// Need to use `fmt` helper function in JavaScript for structured logging.
-Sentry.logger.info(Sentry.logger.fmt`Adding item ${itemId} for user ${userId}`);
+
-Sentry.logger.warn("User %s performed action %s", [userId, actionName], {
- extra: "123",
-});
-```
+SDKs **MAY** attach user information as attributes, guarded by `sendDefaultPii` (since 1.14.0):
-Aside from accepting attributes, these methods can be overloaded to accept severity number or other parameters if required for the language or platform. The Hub/Scope MUST offer the same methods as the static API `Sentry.logger.X`, which is useful for power users who want to use multiple Hubs/Scopes. The Client SHOULD only offer one generic method that accepts the log object and the Scope, such as `captureLog(log, scope)`.
+| Attribute | Description |
+|-----------|-------------|
+| `user.id` | The user ID. Maps to `id` in the [User](/sdk/foundations/data-model/event-payloads/user/) payload. |
+| `user.name` | The username. Maps to `username` in the [User](/sdk/foundations/data-model/event-payloads/user/) payload. |
+| `user.email` | The email address. Maps to `email` in the [User](/sdk/foundations/data-model/event-payloads/user/) payload. |
-Beyond the specified methods, SDKs are free to add any extra helpers as they feel is necessary. For example, they could choose to add specialized decorators or helpers for string template creation.
+
-Below are some example SDK implementations to get you started. These are not finalized versions of the API and individual SDK authors should ensure the logging APIs best fit their platforms. When an SDK implements the logging API, this section should be updated with the SDK's specific implementation.
+### User Agent Parsing
-#### JavaScript
+
-```jsx
-// Browser JavaScript - need to rely on tagged template literals for string templating
-Sentry.logger.info(Sentry.logger.fmt`Adding item ${itemId} for user ${userId}`);
+By default, Relay parses the user agent attached to an incoming log envelope to extract `browser` and `os` information. SDKs **MAY** attach these attributes if they do not forward a user agent:
-// Server-side (Node.js, Bun, Deno) with printf-like syntax
-Sentry.logger.info("Adding item %s for user %s", [itemId, userId], {
- extra: 123,
-});
-```
+| Attribute | Description |
+|-----------|-------------|
+| `browser.name` | Display name of the browser. Maps to `name` in [Browser Context](/sdk/foundations/data-model/event-payloads/contexts/#browser-context). |
+| `browser.version` | Version string of the browser. Maps to `version` in [Browser Context](/sdk/foundations/data-model/event-payloads/contexts/#browser-context). |
-#### Python
+
-```python
-# With f-string like syntax
-Sentry.logger.info('Adding item {item} for user {user}', item=item_id, user=user_id, attributes={ 'extra': 123 });
-```
+### Backend SDK Attributes
-#### PHP
+
-```php
-use function Sentry\logger;
+Backend SDKs (Node.js, Python, PHP, etc.) **SHOULD** attach:
-logger()->info('Adding item %s for user %s', [$item_id, $user_id], ['extra' => 123]);
-```
+| Attribute | Description |
+|-----------|-------------|
+| `server.address` | The server address. Equivalent to [`server_name`](/sdk/foundations/data-model/event-payloads/#optional-attributes) on errors and transactions. |
-#### Java
+
-```java
-import io.sentry.Sentry;
+### Mobile, Desktop, and Native SDK Attributes
-Sentry.logger().info("Adding item %s for user %s", itemId, userId);
+
-// Kotlin
-Sentry.logger().info("Adding item %s for user %s", itemId, userId)
-```
+Mobile, desktop, and native SDKs (Android, Apple, Electron, etc.) **SHOULD** attach:
-#### Apple
+| Attribute | Description |
+|-----------|-------------|
+| `os.name` | OS name. Maps to `name` in [OS Context](/sdk/foundations/data-model/event-payloads/contexts/#os-context). |
+| `os.version` | OS version. Maps to `version` in [OS Context](/sdk/foundations/data-model/event-payloads/contexts/#os-context). |
+| `device.brand` | Device brand. Maps to `brand` in [Device Context](/sdk/foundations/data-model/event-payloads/contexts/#device-context). |
+| `device.model` | Device model. Maps to `model` in [Device Context](/sdk/foundations/data-model/event-payloads/contexts/#device-context). |
+| `device.family` | Device family. Maps to `family` in [Device Context](/sdk/foundations/data-model/event-payloads/contexts/#device-context). |
-```swift
-// Swift
-SentrySDK.logger
- .info(message: "Adding item %s for user %s",
- params: [itemId, userId],
- attributes: ["extra": @"123"]
- )
-```
+
-#### Threading and Concurrency Considerations
+### Buffering
-Both the `Sentry.logger.X` and `Sentry.logger.emit` methods are fire-and-forget (have no return value). This means that the SDK can choose to run these methods on a separate thread or queue them up for processing later. This includes evaluating the string template, and running any internal hooks (like `beforeSendLog`). The SDK should ensure that the logs are sent in the order they are received.
+
-It's important to note that putting everything immediately on a background thread has the downside of losing logs that occur directly before a crash. This will come up for Mobile SDKs. Therefore there will need to be a more robust mechanism if a separate thread is used. This mechanism will vary by platform, and the individual SDK will need to figure out the best approach for their platform.
+SDKs **MUST** buffer logs before sending. A simple initial strategy is flushing when the buffer exceeds 100 items or 5 seconds have passed. The buffer **SHOULD** forward logs to the transport in the scenarios outlined in the [telemetry buffer data forwarding scenarios](/sdk/foundations/processing/telemetry-processor/#data-forwarding-scenarios).
-## SDK Behavior
+SDKs **MUST NOT** send more than 100 logs per envelope (since 1.15.0). Relay is optimized for this limit.
-In general log processing should follow this order:
+SDKs **MUST** enforce a hard limit of 1000 queued log events to prevent out-of-memory issues (since 1.12.0). Logs added beyond this limit are dropped. SDKs **MAY** use a lower limit but **MUST NOT** exceed 1000.
-1. Capture log via [Public APIs](#logger-module) (e.g. `Sentry.logger.info`) or via [SDK integrations](#sdk-integrations).
-1. Check if logging is enabled as per `enableLogs`/`enable_logs` configuration - if not, skip the rest of the steps.
-1. Pass the log to Hub/Scope, which MUST offer the same methods as the static API `Sentry.logger.X`. This is useful for power users who want to use multiple Hubs/Scopes.
-1. Pass the log to the Client, via a generic method that accepts the log object and the `scope`, such as `captureLog(log, scope)`.
-1. Process captured log (attach attributes as per [default attributes](#default-attributes)).
-1. Run `beforeSendLog`/`before_send_log` to filter or modify the log.
-1. Add log to buffer/batch processor as detailed in [buffering](#buffering).
-1. At time of flushing buffer, send array of logs to Sentry via `log` envelope, apply rate limiting as per [data category and rate limiting](#data-category-and-rate-limiting).
+SDKs **MUST NOT** release logging capabilities to users without a buffering implementation.
-
+
+
+### Data Category and Rate Limiting
-An SDK should implement [Tracing without Performance](/sdk/telemetry/traces/tracing-without-performance) before adding support for logs. This is required to ensure that logs are associated with traces and that the correct trace context is sent to Sentry.
+
-
+Logs use the `log_item` data category for rate limiting in Relay. Both `log` and `otel_log` envelopes are covered by this data category. SDKs **MUST** implement this data category. Rate limiting applies as usual with no special behavior for logs.
-### Default Attributes
+SDKs **MUST** track client outcomes for this data category to report how often logs are dropped.
-By default the SDK should attach the following attributes to a log:
+
-1. `sentry.environment`: The environment set in the SDK if defined.
-2. `sentry.release`: The release set in the SDK if defined.
-3. `sentry.sdk.name`: The name of the SDK that sent the log
-4. `sentry.sdk.version`: The version of the SDK that sent the log
-5. `sentry.replay_id`: The replay id of the replay that was active when the log was collected. This should not be set if there was no active replay.
+### SDK Integrations
-```json
-{
- "sentry.environment": "production",
- "sentry.release": "1.0.0",
- "sentry.sdk.name": "sentry.javascript.node",
- "sentry.sdk.version": "9.11.0",
- "sentry.replay_id": "36b75d9fa11f45459412a96c41bdf691"
-}
-```
+
-If the log was parameterized the SDK should attach the following
+SDKs **SHOULD** provide integrations that capture logs from platform logging libraries (e.g., JavaScript's `console`, Python's `logging`, Java's `Log4j`) when `enableLogs`/`enable_logs` is set to `true`.
-1. `sentry.message.template`: The parameterized template string
-2. `sentry.message.parameter.X`: The parameters to the template string. X can either be the number that represent the parameter's position in the template string (`sentry.message.parameter.0`, `sentry.message.parameter.1`, etc) or the parameter's name (`sentry.message.parameter.item_id`, `sentry.message.parameter.user_id`, etc)
+SDKs **MAY** introduce additional options beyond `enableLogs`/`enable_logs` to gate integration-specific functionality (e.g., controlling log appenders added via external config).
-```json
-{
- "sentry.message.template": "Adding item %s for user %s",
- "sentry.message.parameter.0": "item_id",
- "sentry.message.parameter.1": "user_id"
-}
-```
+
-If there are no `sentry.message.parameter.X` attributes included in the log, then the SDK MUST NOT attach a `sentry.message.template` attribute. This is important because it reduces duplicate content in the log and makes PII processing in Sentry much easier as only we don't have to duplicate processing between the log message and the `sentry.message.template` attribute.
+### Tracing Association
-#### SDK Integration Attributes
+
-If a log is generated by an SDK integration, the SDK should also set the `sentry.origin` attribute, as per the [Trace Origin](/sdk/telemetry/traces/trace-origin/) documentation.
+Logs **SHOULD** be associated with traces. If a log is recorded during an active span, SDKs **SHOULD** set the `span_id` property to the active span's ID.
-Logs can be generated in three ways:
+
-1. User calls Sentry’s Logging API directly: SDKs MUST NOT send a `sentry.origin`. As logs are charged based on size, we want to minimize the size of logs, and we **intentionally deviate** from the original [Trace Origin](/sdk/telemetry/traces/trace-origin/) documentation.
+### Replay Association
-2. Captured from a logging library: Use `auto.log.` format. where `` is the relevant integration. For example, the .NET Serilog library emits:
+
-```json
-{ "sentry.origin": "auto.log.serilog" }
-```
+Logs **SHOULD** be associated with replays. If a log is recorded during an active replay, SDKs **SHOULD** set the `sentry.replay_id` attribute to the active replay's ID.
-3. Auto-emitted logs from other instrumented systems: Use the `auto..` format as outlined in [Trace Origin](/sdk/telemetry/traces/trace-origin/) documentation.
+
-```json
-{ "sentry.origin": "auto.db.prisma" }
-```
+### Debug Mode
+
+
+
+If `debug` is set to `true` in SDK init, calls to the Sentry logger API **SHOULD** also print to the console with the appropriate log level. This aids debugging of logging setups.
+
+
-#### User Attributes
+### Client Reports
-SDKs may optionally attach user information as attributes (guarded by `sendDefaultPii`):
+
-1. `user.id`: The user ID. Maps to `id` in the [User](/sdk/foundations/data-model/event-payloads/user/) payload.
-2. `user.name`: The username. Maps to `username` in the [User](/sdk/foundations/data-model/event-payloads/user/) payload.
-3. `user.email`: The email address. Maps to `email` in the [User](/sdk/foundations/data-model/event-payloads/user/) payload.
+SDKs **MUST** report count (`log_item`) and size in bytes (`log_byte`) of discarded log messages. An approximation of log size is sufficient (e.g., by counting as if serialized).
+
+
+
+---
+
+## Wire Format
+
+### `log` Envelope Item
+
+
+
+The `log` envelope item contains an array of log payloads encoded as JSON, allowing multiple logs per envelope item. See the [Log Envelope Item](/sdk/foundations/data-model/envelope-items/#log) documentation for envelope constraints.
```json
{
- "attributes": {
- "user.id": { "value": "123", "type": "string" },
- "user.name": { "value": "john.doe", "type": "string" },
- "user.email": { "value": "john.doe@example.com", "type": "string" }
- }
+ "type": "log",
+ "item_count": 5,
+ "content_type": "application/vnd.sentry.items.log+json"
+}
+{
+ "items": [{..log..}, {..log..}, {..log..}, {..log..}, {..log..}]
}
```
-#### User Agent Parsing
+
-By default, Relay should parse the user agent attached to an incoming log envelope to parse `browser` and `os` information for logs. These attributes should be attached by Relay, but SDKs can attach them if they do not forward a user agent when sending logs to Sentry.
+### `log` Envelope Item Payload
-1. `browser.name`: Display name of the browser application. Maps to `name` in the [Contexts](/sdk/foundations/data-model/event-payloads/contexts/#browser-context) payload.
-2. `browser.version`: Version string of the browser. Maps to `version` in the [Contexts](/sdk/foundations/data-model/event-payloads/contexts/#browser-context) payload.
+
+
+Each log in the `items` array is a JSON object:
```json
{
+ "timestamp": 1544719860.0,
+ "trace_id": "5b8efff798038103d269b633813fc60c",
+ "span_id": "b0e6f15b45c36b12",
+ "level": "info",
+ "body": "User John has logged in!",
+ "severity_number": 9,
"attributes": {
- "browser.name": { "value": "Chrome", "type": "string" },
- "browser.version": { "value": "120.0", "type": "string" }
+ "sentry.message.template": {
+ "value": "User %s has logged in!",
+ "type": "string"
+ },
+ "sentry.message.parameter.0": {
+ "value": "John",
+ "type": "string"
+ }
}
}
```
-#### Backend SDKs
+| Field | Type | Required | Since | Description |
+|-------|------|----------|-------|-------------|
+| `timestamp` | Number | **REQUIRED** | 1.0.0 | Timestamp of the log in seconds since the Unix epoch. |
+| `trace_id` | String | **REQUIRED** | 1.0.0 | Trace ID as 16 random bytes encoded as a hex string (32 characters). **MUST** be grabbed from the current propagation context. |
+| `level` | String | **REQUIRED** | 1.0.0 | Severity level. One of `trace`, `debug`, `info`, `warn`, `error`, `fatal`. |
+| `body` | String | **REQUIRED** | 1.0.0 | The log body/message. |
+| `span_id` | String | **OPTIONAL** | 1.11.0 | Span ID of the active span when the log was collected, as 8 random bytes encoded as a hex string (16 characters). |
+| `severity_number` | Integer | **OPTIONAL** | 1.0.0 | Severity number per [Severity Levels](#severity-levels). Inferred from `level` unless explicitly set. |
+| `attributes` | Object | **OPTIONAL** | 1.0.0 | Key-value pairs of arbitrary data. Values **MUST** declare their type. See [Attributes](/sdk/telemetry/attributes). |
+
+
+
+### `otel_log` Envelope Item Payload
-For backend SDKs (Node.js, Python, PHP, etc.), the SDKs should attach the following:
+
+
+
-1. `server.address`: The address of the server that sent the log. Equivalent to [`server_name`](/sdk/foundations/data-model/event-payloads/#optional-attributes) we attach to errors and transactions.
+The `otel_log` envelope item payload is a JSON object implementing the [OpenTelemetry Log Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/). Multiple `otel_log` items **MAY** be sent per envelope.
```json
{
- "attributes": {
- "server.address": { "value": "foo.example.com", "type": "string" }
- }
+ "severity_text": "info",
+ "body": {
+ "string_value": "User John has logged in!"
+ },
+ "attributes": [
+ {
+ "key": "sentry.message.template",
+ "value": { "string_value": "User %s has logged in!" }
+ },
+ {
+ "key": "sentry.message.parameters.0",
+ "value": { "string_value": "John" }
+ }
+ ],
+ "time_unix_nano": "1741191250694000000",
+ "trace_id": "edec519707974fc8bfccb5a017e17394",
+ "severity_number": 9
}
```
-#### Mobile, Desktop, and Native SDKs
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `severity_text` | String | **REQUIRED** | Severity level. One of `trace`, `debug`, `info`, `warn`, `error`, `fatal`. |
+| `body` | Object | **REQUIRED** | The log body. Contains `string_value` with the message text. |
+| `trace_id` | String | **OPTIONAL** | Trace ID for linking logs to traces and errors. Heavily recommended. |
+| `severity_number` | Integer | **OPTIONAL** | Severity number per [Severity Levels](#severity-levels). |
+| `attributes` | Array\
-1. `os.name`: The name of the operating system. Maps to `name` in the [Contexts](/sdk/foundations/data-model/event-payloads/contexts/#os-context) payload.
-2. `os.version`: The version of the operating system. Maps to `version` in the [Contexts](/sdk/foundations/data-model/event-payloads/contexts/#os-context) payload.
-3. `device.brand`: The brand of the device. Maps to `brand` in the [Contexts](/sdk/foundations/data-model/event-payloads/contexts/#device-context) payload.
-4. `device.model`: The model of the device. Maps to `model` in the [Contexts](/sdk/foundations/data-model/event-payloads/contexts/#device-context) payload.
-5. `device.family`: The family of the device. Maps to `family` in the [Contexts](/sdk/foundations/data-model/event-payloads/contexts/#device-context) payload.
+
-```json
-{
- "attributes": {
- "os.name": { "value": "iOS", "type": "string" },
- "os.version": { "value": "17.0", "type": "string" },
- "device.brand": { "value": "Apple", "type": "string" },
- "device.model": { "value": "iPhone 15 Pro Max", "type": "string" },
- "device.family": { "value": "iPhone", "type": "string" }
- }
-}
+---
+
+## Public API
+
+### Initialization Options
+
+
+
+SDKs **MUST** expose the following configuration options:
+
+| Option | Type | Default | Since | Description |
+|--------|------|---------|-------|-------------|
+| `enableLogs` / `enable_logs` | Boolean | `false` | 1.0.0 | Controls whether log envelopes are generated and sent. If `false`, the SDK **MUST NOT** send logs. |
+| `beforeSendLog` / `before_send_log` | Function | — | 1.0.0 | **OPTIONAL** callback receiving a log object. Returns a modified log or `null` to drop it. |
+
+While logs functionality is in an experimental state, SDKs **SHOULD** put these options in an experimental namespace:
+
+```js
+Sentry.init({
+ _experiments: { enableLogs: true },
+});
```
-#### Future Default Attributes
+
-The SDKs should aim to minimize the number of default attributes attached to a log. Logs are intended to be lightweight, and we want to try to keep the average byte size of a log as small as possible as users will be charged per byte size of logs sent.
+### Logger Module
-We are trying to settle on a balance of debuggability vs. smaller byte size for logs which is why new default attributes should only be added after significant feedback from users and discussion internally with the SDK and ingest teams. There is no hard rule about what exact attributes are allowed, every proposed new attribute will be evaluated on a case-by-case basis.
+
-### Data Category and Rate Limiting
+SDKs **MUST** expose logging methods in a `logger` module or namespace, with one method per [severity level](#severity-levels):
-A new data category for logs has been added to Relay, `log_item`. Both the `log` envelope and `otel_log` envelope is covered by this data category. This will need to implemented in the SDK. Rate limiting applies as usual, there is no special rate limit or rate limiting behaviour for logs. With this data category, client outcomes should be tracked by the SDKs to track how often logs are dropped by the SDK.
+- `Sentry.logger.trace`
+- `Sentry.logger.debug`
+- `Sentry.logger.info`
+- `Sentry.logger.warn`
+- `Sentry.logger.error`
+- `Sentry.logger.fatal`
-### Buffering
+These methods accept a string template and parameters for structured logging. They **MAY** also accept arbitrary attributes.
-SDKs **MUST** buffer logs before sending them. SDKs should keep a buffer of logs and flush it when specific conditions are met. For initial implementation, a simple strategy is fine, for example: flushing logs if the buffer length exceeds 100 items or if 5 seconds have passed. To prevent data loss, the buffer SHOULD forward logs to the transport in the scenarios outlined in the [telemetry buffer data forwarding scenarios](/sdk/foundations/processing/telemetry-processor/#data-forwarding-scenarios).
+The Hub/Scope **MUST** offer the same methods as the static `Sentry.logger.X` API (since 1.10.0). The Client **SHOULD** only offer one generic method (e.g., `captureLog(log, scope)`).
-Relay is optimized for up to 100 logs per envelope. SDKs **MUST NOT** send more than 100 logs per envelope.
+SDKs **MAY** add additional helpers (e.g., decorators, string template helpers) as appropriate for their platform.
-To prevent out-of-memory issues in customer applications, SDKs **MUST** enforce a hard limit of 1000 queued log events. Any logs added beyond this limit are dropped. SDKs **MAY** use a lower limit but **MUST NOT** exceed 1000.
+
-We used to recommend following the [BatchProcessor](/sdk/foundations/processing/telemetry-processor/#batchprocessor-v0), but this page is currently under development. We currently working on a new [telemetry buffer specification](/sdk/foundations/processing/telemetry-processor/) that will replace the BatchProcessor.
+### Threading and Concurrency
-SDKS should NOT release logging capabilities to users if a buffering implementation has not been added to their SDK when adding logging APIs.
+
-### SDK Integrations
+The `Sentry.logger.X` methods are fire-and-forget (no return value). SDKs **MAY** run these methods on a separate thread or queue them for later processing, including evaluating the string template and running internal hooks like `beforeSendLog`.
-SDKs should aim to have it so that console/logger integrations create logs as per the appropriate log level if `enableLogs`/`enable_logs` is set to true. Examples of this include JavaScript's `console` object and Pythons `logging` standard library.
+SDKs **MUST** ensure logs are sent in the order they are received.
-If SDK authors feel the need, they can also introduce additional options to beyond `enableLogs`/`enable_logs` to gate this functionality. For example an option to control log appenders added via external config like with `Log4j` in the Java SDK.
+
-### Behaviour with other Sentry Telemetry
+Putting everything on a background thread risks losing logs that occur directly before a crash. Mobile SDKs will need a more robust mechanism. The individual SDK will need to determine the best approach for their platform.
-#### Tracing
+
-Logs should be associated with traces if possible. If a log is recorded during an active span, the SDK should set the `span_id` property of the log to the span id of the span that was active when the log was collected.
+
-#### Replays
+---
+
+## Examples
+
+### SDK API Usage
+
+
+
+These examples are illustrative, not normative. SDK authors **SHOULD** ensure the API best fits their platform.
+
+
+
+```jsx
+// Browser - tagged template literals
+Sentry.logger.info(Sentry.logger.fmt`Adding item ${itemId} for user ${userId}`);
-Logs should be associated with replays if possible. If a log is recorded during an active replay, the SDK should set the `sentry.replay_id` attribute to the replay id of the replay that was active when the log was collected.
+// Server-side - printf-like syntax
+Sentry.logger.info("Adding item %s for user %s", [itemId, userId], {
+ extra: 123,
+});
+```
+
+```python
+Sentry.logger.info('Adding item {item} for user {user}', item=item_id, user=user_id, attributes={ 'extra': 123 });
+```
+
+```php
+use function Sentry\logger;
+
+logger()->info('Adding item %s for user %s', [$item_id, $user_id], ['extra' => 123]);
+```
+
+```java
+Sentry.logger().info("Adding item %s for user %s", itemId, userId);
+```
-### Other
+```swift
+SentrySDK.logger
+ .info(message: "Adding item %s for user %s",
+ params: [itemId, userId],
+ attributes: ["extra": @"123"]
+ )
+```
-If `debug` is set to `true` in SDK init, calls to the Sentry logger API should also print to the console with the appropriate log level. This will help debugging logging setups.
+### Full `log` Envelope
-## Appendix A: Example `log` Envelope
+A complete `log` envelope with six log entries at different severity levels:
```json
{ "sdk": { "name": "sentry.javascript.browser", "version": "9.15.0" } }
@@ -601,105 +693,8 @@ If `debug` is set to `true` in SDK init, calls to the Sentry logger API should a
}
```
-## Appendix B: `otel_log` Envelope Item Payload
-
-
-
-The `otel_log` envelope item payload is a JSON object that represents an OpenTelemetry Log. Multiple `otel_log` envelope items can be sent in a single envelope. This is implementation of the [OpenTelemetry Log Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/).
-
-```json
-{
- "severity_text": "info",
- "body": {
- "string_value": "User John has logged in!"
- },
- "attributes": [
- {
- "key": "sentry.message.template",
- "value": { "string_value": "User %s has logged in!" }
- },
- {
- "key": "sentry.message.parameters.0",
- "value": { "string_value": "John" }
- }
- ],
- "time_unix_nano": "1741191250694000000",
- "trace_id": "edec519707974fc8bfccb5a017e17394",
- "severity_number": 9
-}
-```
-
-It consists of the following fields:
-
-`severity_text`
-
-: **String, required**. The severity level of the log. One of `trace`, `debug`, `info`, `warn`, `error`, `fatal` (in order of lowest to highest).
-
-`severity_number`
-
-: **Integer, optional**. The severity number of the log. See [Log Severity Number](#log-severity-number) for more information.
-
-`trace_id`
-
-: **Integer, optional**. [HEAVILY RECOMMENDED] The trace id of the log. SDKs should attempt to set this if possible. This is used to link logs to traces and errors in Sentry.
-
-`body`
-
-: **Object, required**. The log body/message.
-
-Example:
-
-```json
-{
- "string_value": "Added item to shopping cart"
-}
-```
-
-`attributes`
-
-: **Array\
+---
-## Client Reports
+## Changelog
-SDKs must report count (`log_item`) and size in bytes (`log_byte`) of discarded log messages. An approximation of log size is sufficient (e.g. by counting as if serialized).
+