diff --git a/.claude/skills/technical-docs/SKILL.md b/.claude/skills/technical-docs/SKILL.md index 4b75b004556fb6..e1920ce49918d0 100644 --- a/.claude/skills/technical-docs/SKILL.md +++ b/.claude/skills/technical-docs/SKILL.md @@ -113,16 +113,6 @@ Good best practice: ## Sentry Docs Specific Patterns -### SplitLayout Usage - -Use `` for side-by-side text/code when: -- The code directly illustrates the text -- Both are needed to understand the concept - -Don't use when: -- Showing a directory structure (use plain code block) -- The text is just "here's an example" (just show the code) - ### PlatformLink Usage Link to related docs rather than repeating content: diff --git a/.github/workflows/bump-api-schema-sha.yml b/.github/workflows/bump-api-schema-sha.yml index 79a1529b3347d6..14b4190e8b8ae6 100644 --- a/.github/workflows/bump-api-schema-sha.yml +++ b/.github/workflows/bump-api-schema-sha.yml @@ -39,7 +39,17 @@ jobs: filepath="src/build/resolveOpenAPI.ts" - sha="$(curl -sSl -H 'Accept: application/vnd.github.VERSION.sha' 'https://api.github.com/repos/getsentry/sentry-api-schema/commits/main')" + # Authenticate to avoid the low unauthenticated rate limit, and fail on + # HTTP errors so an error body never gets written in as the SHA. + sha="$(curl -sSL --fail \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H 'Accept: application/vnd.github.VERSION.sha' \ + 'https://api.github.com/repos/getsentry/sentry-api-schema/commits/main')" + + if [[ ! "$sha" =~ ^[0-9a-f]{40}$ ]]; then + echo "::error::Expected a 40-character commit SHA from the GitHub API, got: $sha" + exit 1 + fi echo "Latest commit to 'getsentry/sentry-api-schema' is $sha" sed -i -e "s|^const SENTRY_API_SCHEMA_SHA =.*$|const SENTRY_API_SCHEMA_SHA = '$sha';|g" "$filepath" diff --git a/app/not-found.tsx b/app/not-found.tsx index 861a1202790d75..af63b954429afd 100644 --- a/app/not-found.tsx +++ b/app/not-found.tsx @@ -43,7 +43,7 @@ export default function NotFound() { {isDeveloperDocs ? ( ) : ( -
+
)}

Page Not Found

diff --git a/app/platforms.json/route.ts b/app/platforms.json/route.ts new file mode 100644 index 00000000000000..e7e23718597af5 --- /dev/null +++ b/app/platforms.json/route.ts @@ -0,0 +1,10 @@ +import {extractPlatforms, getDocsRootNode} from 'sentry-docs/docTree'; + +// Emitted as a static file at build time. Client components load this list +// lazily instead of every page embedding it. +export const dynamic = 'force-static'; + +export async function GET() { + const rootNode = await getDocsRootNode(); + return Response.json(extractPlatforms(rootNode)); +} diff --git a/develop-docs/sdk/telemetry/attachments.mdx b/develop-docs/sdk/telemetry/attachments/index.mdx similarity index 91% rename from develop-docs/sdk/telemetry/attachments.mdx rename to develop-docs/sdk/telemetry/attachments/index.mdx index 417171cdd8f4a6..1eed71fd9984ac 100644 --- a/develop-docs/sdk/telemetry/attachments.mdx +++ b/develop-docs/sdk/telemetry/attachments/index.mdx @@ -170,7 +170,7 @@ When using `Crashpad` as the crash-capturing backend in the Native SDK, the file SDKs **MAY** attach a `flamegraph.json` file containing aggregated call trees, such as those captured for application hangs. The attachment **MUST** use `attachment_type: "event.flamegraph"` and `content_type: "application/json"`. -The format reuses profiling frame objects and debug metadata to support symbolication. Tree nodes describe aggregated call paths and sample counts. +The format reuses profiling frame objects and debug metadata to support symbolication. A flat node table describes aggregated call paths and sample counts. Child references use node indices to avoid deeply nested JSON and allow iterative processing without recursive traversal. #### Flame Graph Attachment Transport @@ -190,13 +190,14 @@ Event context such as release, environment, SDK identity, device, OS, and hang d #### Flame Graph Payload -The top-level object describes one collection of call trees and their shared frame table. +The top-level object describes one collection of call trees and their shared frame and node tables. | Field | Type | Requirement | Description | | ------------ | ---------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | | `version` | String | **REQUIRED** | `"1"` for this wire format. | | `platform` | String | **REQUIRED** | Existing Sentry platform identifier. Used as the default platform for frames. Native Apple frames use `"cocoa"`. | | `frames` | Array of frame objects | **REQUIRED** | Non-empty frame table using the same frame objects as a [V2 profile chunk](/sdk/telemetry/profiles/#profile-data). | +| `nodes` | Array of node objects | **REQUIRED** | Non-empty flat node table. Child and root references are zero-based indices into this array. | | `trees` | Array of tree objects | **REQUIRED** | Non-empty collection of independent call trees. | | `debug_meta` | Debug Meta object | **REQUIRED** for native frames with known images | Existing debug metadata for the process that produced the diagnostic. See [Native Symbolication](#flame-graph-native-symbolication). | @@ -216,7 +217,7 @@ A tree object groups root nodes that share the same sample population. Each obje | Field | Type | Requirement | Description | | ------------------- | -------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------- | -| `roots` | Array of nodes | **REQUIRED** | Non-empty forest of call paths. Roots are the oldest retained callers. | +| `roots` | Array of integers | **REQUIRED** | Non-empty list of zero-based indices into `nodes`. Roots are the oldest retained callers. | | `thread_id` | String | **OPTIONAL** | Actual source thread identifier, if known. Uses the string representation used by profiling samples. | | `thread_attributed` | Boolean | **OPTIONAL** | Whether the diagnostic source identifies this tree's thread as responsible for the reported issue, such as a hang. Omit when unknown. | @@ -224,13 +225,15 @@ Each tree is an independent sample population. Producers **MUST** include `threa ##### Flame Graph Nodes -Each node describes one frame occurrence in a call path. +Each entry in the top-level `nodes` array describes one frame occurrence in a call path. | Field | Type | Requirement | Description | | -------------- | -------------- | ------------ | -------------------------------------------------------------------------------- | | `frame_id` | Integer | **REQUIRED** | Zero-based index into `frames`. **MUST** be between `0` and `frames.length - 1`. | | `sample_count` | Integer | **REQUIRED** | Positive inclusive count of samples containing this call-path prefix. | -| `children` | Array of nodes | **OPTIONAL** | Direct callees. Defaults to `[]` when omitted. | +| `children` | Array of integers | **OPTIONAL** | Zero-based indices into `nodes` for direct callees. Defaults to `[]` when omitted. | + +Root and child indices **MUST** be between `0` and `nodes.length - 1`. Node references **MUST** form independent trees without cycles or shared nodes. Recursive calls use separate nodes that **MAY** reference the same `frame_id`. Paths **MUST** run from caller to callee. Each root-to-leaf path is one observed call path, potentially ending before the true bottom or top of the stack if the source was incomplete. @@ -248,13 +251,13 @@ Frame addresses **MUST** follow the existing [`instruction_addr` and `addr_mode` Symbolication **MUST** preserve captured addresses, addressing modes, and debug images. Resolved function names and source locations **MUST** populate the standard profiling frame fields. Unresolved frames **MUST** retain their original data. -Consumers **MUST** track symbolication state and skip symbolication for already-processed payloads. If symbolication is rerun, it **MUST** start from the original, unexpanded frames and trees. +Consumers **MUST** track symbolication state and skip symbolication for already-processed payloads. If symbolication is rerun, it **MUST** start from the original, unexpanded frames, nodes, and trees. ##### Flame Graph Inline Frames Compiler-inlined functions share a physical stack frame with their caller. [Native symbolication](/ingestion/symbolicator/#native-symbolication) can recover these functions as separate logical frames. -A processor that expands inline frames **MUST** replace each affected node occurrence with a caller-to-callee chain, assign the original `sample_count` to every node in that chain, and attach the original children to its innermost node. The expansion **MUST** preserve the tree's total sample count. Frame-table changes **MUST** update all affected indices. +A processor that expands inline frames **MUST** replace each affected node occurrence with a caller-to-callee chain, assign the original `sample_count` to every node in that chain, and attach the original children to its innermost node. The expansion **MUST** preserve the tree's total sample count. Frame-table changes **MUST** update all affected `frame_id` values. Node-table changes **MUST** update all affected `roots` and `children` indices. #### Flame Graph Example @@ -290,21 +293,21 @@ This example contains 10 samples. Six continue from `main` into `process` and fo "lineno": 42 } ], + "nodes": [ + { + "frame_id": 0, + "sample_count": 10, + "children": [1] + }, + { + "frame_id": 1, + "sample_count": 6 + } + ], "trees": [ { "thread_attributed": true, - "roots": [ - { - "frame_id": 0, - "sample_count": 10, - "children": [ - { - "frame_id": 1, - "sample_count": 6 - } - ] - } - ] + "roots": [0] } ] } @@ -349,46 +352,7 @@ Attachment placeholders use item type `"attachment"` with content type `"applica SDKs **MUST** send placeholders in the same envelope as the event the file is attached to. -**Workflow:** - -1. If an attachment is larger than ~100 MiB, upload it to the [TUS](https://tus.io/protocols/resumable-upload#creation-with-upload)-conformant upload endpoint: - 1. Create the upload: - - ```shell - curl -X POST https://o0.ingest.sentry.io/api/0/upload/ \ - --header "Tus-Resumable: 1.0.0" \ - --header "Upload-Length: ${FILE_SIZE}" \ - --header "Upload-Metadata: sentry $(echo -n '{"attachment_type":"event.attachment"}' | base64)" - ``` - - The `Upload-Metadata` header follows the [TUS metadata format](https://tus.io/protocols/resumable-upload#upload-metadata). Sentry recognizes a single key, `sentry`, the value of which **MUST** be the Base64 encoding of a UTF-8 JSON object describing the attachment: - - ```json - { - "attachment_type": "event.attachment" - } - ``` - - | Field | Type | Required | Description | - | ----------------- | ------ | ------------ | ------------------------------------------------------------------ | - | `attachment_type` | String | **REQUIRED** | One of the values listed in [Attachment Types](#attachment-types). | - - 1. Get the location response header: - ``` - HTTP/1.1 201 Created - Location: https://o0.ingest.sentry.io/api/0/upload/24e533e02ec3bc40c387f1a0e460e216/ - Tus-Resumable: 1.0.0 - ``` - 1. Upload the file: - ```shell - curl -X PATCH https://o0.ingest.sentry.io/api/0/upload/24e533e02ec3bc40c387f1a0e460e216/ \ - --header "Tus-Resumable: 1.0.0" \ - --header "Content-Type: application/offset+octet-stream" \ - --header "Upload-Offset: 0" \ - --data @myfile.log - ``` - -1. Upon successful upload, attach a placeholder item to the event envelope, using the `Location` header from the upload response. +See [Resumable Uploads](/sdk/telemetry/attachments/upload/) for a detailed guide on how to obtain an attachment placeholder. diff --git a/develop-docs/sdk/telemetry/attachments/upload.mdx b/develop-docs/sdk/telemetry/attachments/upload.mdx new file mode 100644 index 00000000000000..563e9016890a98 --- /dev/null +++ b/develop-docs/sdk/telemetry/attachments/upload.mdx @@ -0,0 +1,134 @@ +--- +title: Resumable Uploads +--- + + + The upload endpoint is an experimental feature which requires the `projects:resumable-uploads` feature flag to be enabled. + + +For attachments larger than ~100 MiB, SDKs **SHOULD** use the resumable upload endpoint. +This allows the client to upload attachments that are much larger than what the envelope endpoint currently allows, and to resume an upload when the stream got interrupted. The endpoint is based on the [tus resumable upload protocol](https://tus.io/protocols/resumable-upload). + +## Workflow + +1. Create the upload to receive a pre-signed URL to the assigned upload location: + + ```shell + curl -X POST https://o0.ingest.sentry.io/api/0/upload/ \ + --header "Tus-Resumable: 1.0.0" \ + --header "Upload-Length: ${FILE_SIZE}" \ + --header "Upload-Metadata: sentry $(echo -n '{"attachment_type":"event.attachment"}' | base64)" + ``` + + The `Upload-Length` header **MUST** be specified. Sentry does not support the [`creation-defer-length` extension](https://tus.io/protocols/resumable-upload#post) of the tus protocol. + + The `Upload-Metadata` header follows the [TUS metadata format](https://tus.io/protocols/resumable-upload#upload-metadata). Sentry recognizes a single key, `sentry`, the value of which **MUST** be the Base64 encoding of a UTF-8 JSON object describing the attachment: + + ```json + { + "attachment_type": "event.attachment" + } + ``` + + | Field | Type | Required | Description | + | ----------------- | ------ | ------------ | ------------------------------------------------------------------ | + | `attachment_type` | String | **REQUIRED** | One of the values listed in [Attachment Types](/sdk/telemetry/attachments/#attachment-types). | + +1. Parse response headers necessary for proceeding: + + 1. `Upload-Chunk-Granularity` (bytes) - Every `PATCH` request made to location below must be a multiple of this number (except for the final request). + 1. `Upload-Min-Chunk-Size` (bytes) - Every `PATCH` request made to location below must be at least this large (except for the final request). + 1. `Upload-Max-Chunk-Size` (bytes) - No `PATCH` request made to location below may be larger than this. If the file is larger than the maximum chunk size, split it into multiple requests (see `Upload-Offset` below). + 1. `Location` (URL) - The target of subsequent `PATCH` requests. + + Example response: + + ``` + HTTP/1.1 201 Created + Tus-Resumable: 1.0.0 + Tus-Extension: creation + Upload-Chunk-Granularity: 256 + Upload-Min-Chunk-Size: 1048576 + Upload-Max-Chunk-Size: 1073741824 + Location: https://o0.ingest.sentry.io/api/0/upload/24e533e02ec3bc40c387f1a0e460e216/ + ``` + + If the server replies with a [501 Not Implemented](https://www.rfc-editor.org/info/rfc9110/#status.501) response, the SDK **SHOULD** either fall back to submitting the attachment in an envelope (if it is [small enough](/sdk/foundations/envelopes/#size-limits)), or drop the attachment. + +1. Upload the first chunk: + + ```shell + head -c 1073741824 myfile.log | \ # Take the first `Max-Chunk-Size` bytes + curl -X PATCH https://o0.ingest.sentry.io/api/0/upload/24e533e02ec3bc40c387f1a0e460e216/ \ + --header "Tus-Resumable: 1.0.0" \ + --header "Content-Type: application/offset+octet-stream" \ + --header "Upload-Offset: 0" \ + --header "X-Decoded-Content-Length: 1073741824" + --data-binary @- + ``` + + The client **SHOULD** compress the request body to speed up the upload (see [Request Compression](/sdk/foundations/transport/compression/)). When it does, the `Content-Length` header refers to the compressed length of the current chunk. Therefore, the client **MUST** send the custom `X-Decoded-Content-Length` header containing the original, uncompressed length of the current chunk, to inform the storage backend about its size upfront. + +1. Resume the upload: + + Regardless of whether the previous `PATCH` request was successful, the client **SHOULD** attempt to resume the upload if it is incomplete. If the previous response from the server reports the `Upload-Offset` header, then this is the offset in bytes from which to resume. + + If the server did _not_ communicate the current server offset through the `Upload-Offset` header, or the response has been lost (for example, after a process restart), the client **MUST** make a `HEAD` request to the upload location to retrieve the current state: + + ```shell + curl -X HEAD https://o0.ingest.sentry.io/api/0/upload/24e533e02ec3bc40c387f1a0e460e216/ + ``` + + Example response: + + ``` + HTTP/1.1 204 No Content + Tus-Resumable: 1.0.0 + Upload-Offset: 1073741824 + Cache-Control: no-store + ``` + + Plug the returned `Upload-Offset` into the next patch request to resume: + + ```shell + tail -c 1073741825 myfile.log | \ # Skip the offset + curl -X PATCH https://o0.ingest.sentry.io/api/0/upload/24e533e02ec3bc40c387f1a0e460e216/ \ + --header "Tus-Resumable: 1.0.0" \ + --header "Content-Type: application/offset+octet-stream" \ + --header "Upload-Offset: 1073741824" \ + --header "X-Decoded-Content-Length: 2345256" \ # remaining file size + --data-binary @- + ``` + +1. Finalize the upload: + + Once the total number of uploaded bytes matches the `Upload-Length` that was announced in the initial `POST` request, the server returns the **final** location of the upload in the `Location` response header: + + ``` + HTTP/1.1 204 No Content + Tus-Resumable: 1.0.0 + Upload-Offset: 1076087080 + Location: https://o0.ingest.sentry.io/api/0/upload/24e533e02ec3bc40c387f1a0e460e216/?upload_length=1076087080&upload_signature=..." + ``` + + SDKs **MUST** use this location to attach a [placeholder item](/sdk/telemetry/attachments/#attachment-placeholders) to the event envelope. SDKs **MUST NOT** use the `Location` header from the initial `POST` request, or any intermediate request, because it may not contain all the fields needed to create a valid placeholder. + +## Common Error Responses + +This table lists some of the errors you might encounter while uploading. + +| Status | Error Text | Solution | +| ----------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | +| 400 Bad Request | `Missing X-Decoded-Content-Length header` | Specify the size of the request body before compression. | +| 400 Bad Request | `non-final chunk {chunk_length} is smaller than upload granularity {upload_granularity}` | Use chunks of at least `Upload-Min-Chunk-Size` bytes, in multiples of `Upload-Chunk-Granularity`, except for the final chunk. | +| 409 Conflict | `upload offset mismatch (server holds {offset} bytes)` | Make a `HEAD` request to obtain the server's current state. | +| 413 Payload Too Large | `Chunk of {chunk_length} bytes exceeds the remaining {remaining} bytes` | You are trying to upload more than you initially declared with `Upload-Length`. Cap the file or look for bugs in the counting logic. | +| 413 Payload Too Large | `length limit exceeded` | The request's `Content-Length` exceeds the server's request body size limit. Send smaller chunks. | +| 413 Payload Too Large | _empty response_ | Split your file into smaller chunks. | +| 501 Not Implemented | `upload error: resumable upload declined` | Send the attachment in an envelope instead, or drop it if it is too large. | +| 503 Service Unavailable | | Retry. | +| 504 Gateway Timeout | | Retry. | + +## Compression + +The byte sizes in the headers refer to the request body _before_ compression, that is, before applying any form of `Content-Encoding`. This applies to `Upload-Chunk-Granularity`, `Upload-Min-Chunk-Size`, `Upload-Max-Chunk-Size` and `Upload-Offset`. The server interprets `Content-Encoding` on a `PATCH` request as a self-contained transport optimization that only concerns the current request in isolation, not the full upload. diff --git a/docs/concepts/key-terms/tracing/img/trace-pin-attribute.png b/docs/concepts/key-terms/tracing/img/trace-pin-attribute.png new file mode 100644 index 00000000000000..be508e5ffb81ac Binary files /dev/null and b/docs/concepts/key-terms/tracing/img/trace-pin-attribute.png differ diff --git a/docs/concepts/key-terms/tracing/img/trace-pinned-attributes.png b/docs/concepts/key-terms/tracing/img/trace-pinned-attributes.png new file mode 100644 index 00000000000000..898cdc893d55b3 Binary files /dev/null and b/docs/concepts/key-terms/tracing/img/trace-pinned-attributes.png differ diff --git a/docs/concepts/key-terms/tracing/img/trace-time-compression.png b/docs/concepts/key-terms/tracing/img/trace-time-compression.png new file mode 100644 index 00000000000000..17fea6e2df53f3 Binary files /dev/null and b/docs/concepts/key-terms/tracing/img/trace-time-compression.png differ diff --git a/docs/concepts/key-terms/tracing/img/trace-web-vital-navigation.gif b/docs/concepts/key-terms/tracing/img/trace-web-vital-navigation.gif new file mode 100644 index 00000000000000..58ad0868f53ecf Binary files /dev/null and b/docs/concepts/key-terms/tracing/img/trace-web-vital-navigation.gif differ diff --git a/docs/concepts/key-terms/tracing/trace-view.mdx b/docs/concepts/key-terms/tracing/trace-view.mdx index 25aff5af64f0e6..23c1c96b3d173b 100644 --- a/docs/concepts/key-terms/tracing/trace-view.mdx +++ b/docs/concepts/key-terms/tracing/trace-view.mdx @@ -24,6 +24,34 @@ On the left side is a list of operations, and on the right is their duration and +### Time compression + +Time compression shrinks empty gaps between spans in the waterfall. This brings spans closer together so you can see more of the trace at once and focus on where work happens. + +![Trace waterfall with time compression enabled, showing a shaded gap between spans](./img/trace-time-compression.png) + +### Pin an attribute + +Pin an [attribute](/concepts/key-terms/tracing/#what-are-span-attributes-and-metrics) to compare its values across spans without opening each span individually. Pinned attributes appear as columns in the waterfall and stay visible as you explore the trace. + +To pin an attribute: + +1. Select a span in the waterfall to open its side panel. +2. Find the attribute in the **Attributes** tree. +3. Open the attribute's actions menu and select **Pin to waterfall**. + +![Attribute actions menu with Pin to waterfall highlighted](./img/trace-pin-attribute.png) + +For example, pin `sdk.name` to see which SDK recorded each span. + +![Trace waterfall with sdk.name pinned as a column alongside each span](./img/trace-pinned-attributes.png) + +### Jump to a Web Vital + +Click a [Web Vital](/product/dashboards/sentry-dashboards/frontend/web-vitals/web-vitals-concepts/) pill in the trace summary or on the waterfall to zoom to the point where Sentry recorded that metric. The waterfall brings the surrounding spans into view so you can investigate what happened at that moment. + +![Trace waterfall zooming to a Web Vital after clicking its pill](./img/trace-web-vital-navigation.gif) + ### Previous and Next Traces As users interact with an application, they generate multiple traces. For example, when a user loads a page in their browser and then navigates to another page, this creates two separate traces: one for the initial pageload and another for the subsequent navigation. By default, Sentry will link the traces together. diff --git a/docs/concepts/otlp/forwarding/pipelines/collector.mdx b/docs/concepts/otlp/forwarding/pipelines/collector.mdx index e420c2d8f1526f..c36205566f8fc7 100644 --- a/docs/concepts/otlp/forwarding/pipelines/collector.mdx +++ b/docs/concepts/otlp/forwarding/pipelines/collector.mdx @@ -18,18 +18,11 @@ Before you begin, ensure you have: ## Step 1: Get Your Sentry OTLP Credentials - - - - Find these in [Sentry Project Settings](https://sentry.io/orgredirect/organizations/:orgslug/settings/projects/:projectId/keys/) under **Client Keys (DSN)** > **OpenTelemetry (OTLP)**. - Use the **combined endpoint** if sending both logs and traces - The Collector appends `/v1/logs` or `/v1/traces` automatically - - - ```bash # Logs endpoint ___OTLP_LOGS_URL___ @@ -44,25 +37,14 @@ ___OTLP_URL___ x-sentry-auth: sentry sentry_key=___PUBLIC_KEY___ ``` - - - - ## Step 2: Configure the Collector Update your OpenTelemetry Collector configuration to add the `otlphttp` exporter pointing to Sentry. - - - - ### Logs Only Use `logs_endpoint` to forward only logs to Sentry. - - - ```yaml {filename:otel-collector.yaml} exporters: otlphttp/sentry: @@ -73,19 +55,10 @@ exporters: encoding: proto ``` - - - - - - ### Traces Only Use `traces_endpoint` to forward only traces to Sentry. - - - ```yaml {filename:otel-collector.yaml} exporters: otlphttp/sentry: @@ -96,19 +69,10 @@ exporters: encoding: proto ``` - - - - - - ### Logs and Traces Use the combined `endpoint` to forward both logs and traces. The Collector appends the appropriate path for each signal type. - - - ```yaml {filename:otel-collector.yaml} exporters: otlphttp/sentry: @@ -119,10 +83,6 @@ exporters: encoding: proto ``` - - - - ## Routing to Multiple Projects @@ -131,10 +91,6 @@ For simpler multi-project routing, consider the [Sentry Exporter](/concepts/otlp - - - - Sentry's OTLP endpoints are project-specific. To route telemetry from different services to different Sentry projects using `otlphttp`, use the [routing connector](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/connector/routingconnector). This example routes logs to different Sentry projects based on the `service.name` attribute: @@ -142,9 +98,6 @@ This example routes logs to different Sentry projects based on the `service.name - Logs with `service.name: "service-b"` go to Project B - All other logs go to Project A (the default) - - - ```yaml {filename:otel-collector.yaml} receivers: otlp: @@ -187,7 +140,3 @@ service: receivers: [routing] exporters: [otlphttp/project-b] ``` - - - - diff --git a/docs/concepts/otlp/forwarding/pipelines/fluentbit.mdx b/docs/concepts/otlp/forwarding/pipelines/fluentbit.mdx index 514341e37d0b60..5c7400d09bf1b6 100644 --- a/docs/concepts/otlp/forwarding/pipelines/fluentbit.mdx +++ b/docs/concepts/otlp/forwarding/pipelines/fluentbit.mdx @@ -16,15 +16,8 @@ Before you begin, ensure you have: ## Step 1: Get Your Sentry OTLP Credentials - - - - Find these in [Sentry Project Settings](https://sentry.io/orgredirect/organizations/:orgslug/settings/projects/:projectId/keys/) under **Client Keys (DSN)** > **OpenTelemetry (OTLP)**. - - - ```bash # Logs endpoint ___OTLP_LOGS_URL___ @@ -36,25 +29,14 @@ ___OTLP_TRACES_URL___ x-sentry-auth: sentry sentry_key=___PUBLIC_KEY___ ``` - - - - ## Step 2: Configure Fluent Bit Add the OpenTelemetry output plugin to your Fluent Bit configuration to forward data to Sentry. - - - - ### Logs Only Use `logs_uri` to forward only logs to Sentry. - - - ```yaml {filename:fluent-bit.yaml} pipeline: outputs: @@ -81,19 +63,10 @@ pipeline: Header x-sentry-auth sentry sentry_key=___PUBLIC_KEY___ ``` - - - - - - ### Traces Only Use `traces_uri` to forward only traces to Sentry. - - - ```yaml {filename:fluent-bit.yaml} pipeline: outputs: @@ -120,19 +93,10 @@ pipeline: Header x-sentry-auth sentry sentry_key=___PUBLIC_KEY___ ``` - - - - - - ### Logs and Traces Include both `logs_uri` and `traces_uri` to forward logs and traces to Sentry. - - - ```yaml {filename:fluent-bit.yaml} pipeline: outputs: @@ -161,10 +125,6 @@ pipeline: Header x-sentry-auth sentry sentry_key=___PUBLIC_KEY___ ``` - - - - ## Optional Configuration Fluent Bit's OpenTelemetry output plugin supports additional options for fine-tuning your setup: diff --git a/docs/concepts/otlp/forwarding/pipelines/sentry-exporter.mdx b/docs/concepts/otlp/forwarding/pipelines/sentry-exporter.mdx index 700a99ef282970..1f2cef1258f708 100644 --- a/docs/concepts/otlp/forwarding/pipelines/sentry-exporter.mdx +++ b/docs/concepts/otlp/forwarding/pipelines/sentry-exporter.mdx @@ -74,15 +74,8 @@ In your Sentry account, go to **[General Settings](https://sentry.io/orgredirect ## Basic Configuration - - - - By default, the exporter routes telemetry based on `service.name`. A service with `service.name: payments-api` sends to a Sentry project with slug `payments-api`. - - - ```yaml {filename:otel-collector-config.yaml} receivers: otlp: @@ -113,16 +106,8 @@ service: exporters: [sentry] ``` - - - - ## Routing Options - - - - ### Automatic Project Creation When services spin up dynamically (Kubernetes deployments, serverless functions), you may not have pre-created Sentry projects. Enable `auto_create_projects` to provision them on-demand. @@ -132,9 +117,6 @@ When services spin up dynamically (Kubernetes deployments, serverless functions) may be dropped while provisioning completes. - - - ```yaml exporters: sentry: @@ -142,21 +124,12 @@ exporters: auto_create_projects: true ``` - - - - - - ### Custom Project Mapping When your service names don't match your Sentry project slugs (legacy naming, organizational conventions), map them explicitly. Services not in the mapping fall back to using `service.name` as the project slug. - - - ```yaml exporters: sentry: @@ -168,19 +141,10 @@ exporters: api-gateway: ecommerce-gateway ``` - - - - - - ### Routing by Different Attributes Route by environment, team, or any other resource attribute instead of service name. - - - ```yaml exporters: sentry: @@ -192,10 +156,6 @@ exporters: staging: staging-monitoring ``` - - - - ## Rate Limiting The exporter respects Sentry's rate limits automatically: diff --git a/docs/concepts/otlp/forwarding/pipelines/vector.mdx b/docs/concepts/otlp/forwarding/pipelines/vector.mdx index 729b3754c0929f..467c6326ec324c 100644 --- a/docs/concepts/otlp/forwarding/pipelines/vector.mdx +++ b/docs/concepts/otlp/forwarding/pipelines/vector.mdx @@ -16,15 +16,8 @@ Before you begin, ensure you have: ## Step 1: Get Your Sentry OTLP Credentials - - - - Find these in [Sentry Project Settings](https://sentry.io/orgredirect/organizations/:orgslug/settings/projects/:projectId/keys/) under **Client Keys (DSN)** > **OpenTelemetry (OTLP)**. - - - ```bash # Logs endpoint ___OTLP_LOGS_URL___ @@ -33,10 +26,6 @@ ___OTLP_LOGS_URL___ x-sentry-auth: sentry sentry_key=___PUBLIC_KEY___ ``` - - - - ## Step 2: Configure Vector Choose your configuration based on your data source: @@ -46,10 +35,6 @@ Choose your configuration based on your data source: ## Option A: Forwarding OTLP Data - - - - If you're receiving data that's already in OTLP format (from an OpenTelemetry SDK or collector), you can forward it directly to Sentry using the `otlp` codec without any transformation. @@ -58,9 +43,6 @@ The `otlp` codec requires Vector version [0.51.0](https://vector.dev/releases/0. - - - ```yaml {filename:vector.yaml} sources: otel_source: @@ -86,10 +68,6 @@ sinks: codec: otlp ``` - - - - ## Option B: Transforming Non-OTLP Data If your logs come from non-OTLP sources (files, syslog, etc.), you need to use a [remap transform](https://vector.dev/docs/reference/configuration/transforms/remap/) with VRL (Vector Remap Language) to convert your data into the OTEL format before sending to Sentry. @@ -127,10 +105,6 @@ The OpenTelemetry log format requires a specific structure with `resourceLogs`, ### Example: Forwarding File Logs - - - - This example reads logs from a file and forwards them to Sentry. The remap transform: @@ -139,9 +113,6 @@ The remap transform: - Maps file metadata to attributes - Cleans up original fields - - - ```yaml {filename:vector.yaml} sources: app_logs: @@ -202,16 +173,8 @@ sinks: codec: otlp ``` - - - - ### Example: Forwarding Syslog - - - - For syslog data, you can map severity levels to OTEL severity. The remap transform: @@ -219,9 +182,6 @@ The remap transform: - Preserves syslog metadata as attributes - Handles the syslog-specific fields - - - ```yaml {filename:vector.yaml} sources: syslog_input: @@ -299,10 +259,6 @@ sinks: codec: otlp ``` - - - - ## VRL Remap Reference Here are the key VRL functions you'll use when building OTEL log records: diff --git a/docs/concepts/search/searchable-properties/events.mdx b/docs/concepts/search/searchable-properties/events.mdx index bc18ef46253c6b..5e3f246e714c08 100644 --- a/docs/concepts/search/searchable-properties/events.mdx +++ b/docs/concepts/search/searchable-properties/events.mdx @@ -48,8 +48,15 @@ Returns results with matching averages for the field selected. The field can be ### `count_if(column,operator,value)` +This syntax is only available on errors Returns results with a matching count that satisfy the condition passed to the parameters of the function. +### ``count_if(`column:value OR other_column:value2`)`` + +This syntax is only available on Spans, Logs and Trace Metrics +Returns results with a matching count that satisfy the condition passed to the first parameter of the function, the _if +combinator can be added to most functions + - **Type:** number ### `count_miserable(field,threshold)` diff --git a/docs/platforms/android/integrations/jetpack-compose/index.mdx b/docs/platforms/android/integrations/jetpack-compose/index.mdx index 2aa348b379e881..0b62b372c9a0c2 100644 --- a/docs/platforms/android/integrations/jetpack-compose/index.mdx +++ b/docs/platforms/android/integrations/jetpack-compose/index.mdx @@ -3,18 +3,18 @@ title: Jetpack Compose caseStyle: camelCase supportLevel: production sdk: sentry.java.compose -description: Learn more about the Sentry Compose integration. +description: Learn more about Sentry's integrations for Jetpack Compose. categories: - mobile og_image: /og-images/platforms-android-integrations-jetpack-compose.png --- -The `sentry-compose-android` library provides [Jetpack Compose](https://developer.android.com/jetpack/androidx/releases/compose) support in the following areas: +The `sentry-compose-android` and `sentry-android-navigation3` libraries provide [Jetpack Compose](https://developer.android.com/compose) support in the following areas: - `@Composable` performance metrics -- Transaction and breadcrumb support for user interactions (clicks, swipes and scroll gestures) -- Transaction and breadcrumb support for navigation events -- Support for View Hierarchies +- Support for user interactions (clicks, swipes and scroll gestures) +- Support for navigation +- Support for debugging view hierarchies ## Performance Metrics @@ -28,8 +28,12 @@ With Jetpack Compose performance metrics the Sentry Android SDK can automaticall This feature requires an underlying transaction to attach it's spans to. Transactions can be created manually or automatically by configuring -- Activity instrumentation -- [Navigation Instrumentation](#jetpack-compose-navigation) +- + Activity instrumentation + +- + Navigation instrumentation + - [User Interactions](#user-interactions) @@ -132,231 +136,19 @@ fun LoginScreen() { } ``` - - -If a `@Composable` doesn't have a `.sentryTag` or a `.testTag` modifier applied, both breadcrumbs and transactions won't be captured because they can't be uniquely identified. -To automatically generate tags, refer to the docs about our Sentry Kotlin Compiler Plugin. - - - - - -If you want to customize the recorded breadcrumbs/transactions, you can skip to [the section below](#customize-the-recorded-breadcrumbtransaction). - - - -## Jetpack Compose Navigation +#### Customize the Recorded Breadcrumb/Transaction -In this section, we get you up and running with Sentry's Compose Navigation Integration, so that it will automatically add a breadcrumb and start a transaction for each navigation event. +User interaction instrumentation uses the `sentryTag` or `testTag` value to identify the composable in the recorded breadcrumb and transaction. Keep these tags stable and free of PII or other sensitive data. -![Jetpack Compose Navigation Breadcrumbs](./img/jetpack-compose-navigation.png) - -### Auto-Installation With the Sentry Android Gradle Plugin - -#### Install - -If you're using the [Sentry Android Gradle Plugin](/platforms/android/configuration/gradle/), the Jetpack Compose Navigation Integration is automatically applied, and both breadcrumbs and transactions are automatically created for every navigation event. - -Add the Sentry Android Gradle plugin in `build.gradle`: - -```groovy -plugins { - id "io.sentry.android.gradle" version "{{@inject packages.version('sentry.java.android.gradle-plugin', '3.0.0') }}" -} -``` - -```kotlin -plugins { - id("io.sentry.android.gradle") version "{{@inject packages.version('sentry.java.android.gradle-plugin', '3.0.0') }}" -} -``` +If needed, you can filter sensitive data from breadcrumbs and transactions before they're sent to Sentry via the `SentryOptions.BeforeBreadcrumbCallback` and `SentryOptions.BeforeSendTransactionCallback`, respectively. -Learn more about the Sentry Android Gradle plugin in our [Gradle](/platforms/android/configuration/gradle/) documentation. Details about auto-installation can be found in the [Auto Instrumentation](/platforms/android/configuration/gradle/#tracing-auto-instrumentation) section. +If a `@Composable` doesn't have a `.sentryTag` or a `.testTag` modifier applied, both breadcrumbs and transactions won't be captured because they can't be uniquely identified. +To automatically generate tags, refer to the docs about our Sentry Kotlin Compiler Plugin. -#### Disable - -If you want to disable the Jetpack Compose instrumentation feature, you can adapt your `build.gradle(.kts)` file like so: - -```groovy -import io.sentry.android.gradle.extensions.InstrumentationFeature - -sentry { - tracingInstrumentation { - enabled = true - features = EnumSet.allOf(InstrumentationFeature) - InstrumentationFeature.COMPOSE - } -} -``` - -```kotlin -import java.util.EnumSet -import io.sentry.android.gradle.extensions.InstrumentationFeature - -sentry { - tracingInstrumentation { - enabled.set(true) - features.set(EnumSet.allOf(InstrumentationFeature::class.java) - InstrumentationFeature.COMPOSE) - } -} -``` - -### Manual Installation - -#### Install - -Sentry captures data by adding a `withSentryObservableEffect` extension function to `NavHostController`. To add the Navigation integration, install the [Android SDK](/platforms/android/), then add the `sentry-compose` dependency using Gradle: - -```groovy -implementation 'io.sentry:sentry-android:{{@inject packages.version('sentry.java.android', '6.2.0') }}' -implementation 'io.sentry:sentry-compose-android:{{@inject packages.version('sentry.java.compose.android', '6.2.0') }}' -``` - -#### Configure - -Configuration should happen in the respective `@Composable` function, once you obtain an instance of `NavHostController`: - -```kotlin -import androidx.navigation.compose.NavHost -import androidx.navigation.compose.rememberNavController -import io.sentry.compose.withSentryObservableEffect - -val navController = rememberNavController().withSentryObservableEffect( - enableNavigationBreadcrumbs = true, // enabled by default - enableNavigationTracing = true // enabled by default -) -NavHost( - navController = navController -) { - ... -} -``` - -By default, the navigation transaction finishes automatically after it reaches the specified [idleTimeout](/platforms/android/configuration/options/#idleTimeout) and all of its child spans are finished. You can customize the timeout to your needs. - -### Verify - -This snippet includes a sample `Activity` with a couple of navigation events between composables and captures an intentional message, so you can test that everything is working as soon as you set it up: - -```kotlin -import android.os.Bundle -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Button -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp -import androidx.navigation.NavHostController -import androidx.navigation.NavType -import androidx.navigation.compose.NavHost -import androidx.navigation.compose.composable -import androidx.navigation.compose.rememberNavController -import io.sentry.Sentry -import io.sentry.compose.withSentryObservableEffect - -class ComposeActivity : ComponentActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - setContent { - val navController = rememberNavController().withSentryObservableEffect() - SampleNavigation(navController) - } - } -} - -@Composable -fun SampleNavigation(navController: NavHostController) { - NavHost( - navController = navController, - startDestination = "first" - ) { - composable("first") { - First( - navigateToSecond = { navController.navigate("second") } - ) - } - composable("second") { - Second() - } - } -} - -@Composable -fun First( - navigateToSecond: () -> Unit -) { - Column( - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.fillMaxSize() - ) { - Button( - onClick = { navigateToSecond() }, - modifier = Modifier.padding(top = 32.dp) - ) { - Text("Navigate to Second") - } - Button( - onClick = { Sentry.captureMessage("Some message from Compose.") }, - modifier = Modifier.padding(top = 32.dp) - ) { - Text("Message from Compose") - } - } -} - -@Composable -fun Second() { - Column( - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.fillMaxSize() - ) { - Text("Second Screen") - } -} -``` - -## Customize the Recorded Breadcrumb/Transaction - -By default, the Navigation integration captures route arguments as additional data on breadcrumbs and transactions. In case the arguments contain any PII data, you can strip it out by way of `BeforeBreadcrumbCallback` and `EventProcessor` respectively. To do that, [manually initialize](/platforms/android/manual-setup/#configuration-via-sentryoptions) the SDK and add the following snippet: - -```kotlin -import io.sentry.EventProcessor -import io.sentry.android.core.SentryAndroid -import io.sentry.SentryOptions.BeforeBreadcrumbCallback -import io.sentry.android.navigation.SentryNavigationListener - -SentryAndroid.init(this) { options -> - options.beforeBreadcrumb = BeforeBreadcrumbCallback { breadcrumb, hint -> - if (SentryNavigationListener.NAVIGATION_OP == breadcrumb.category) { - breadcrumb.data.remove("from_arguments") - breadcrumb.data.remove("to_arguments") - } - breadcrumb - } - options.addEventProcessor(object : EventProcessor { - override fun process(transaction: SentryTransaction, hint: Hint): SentryTransaction? { - if (SentryNavigationListener.NAVIGATION_OP == transaction.contexts.trace.operation) { - transaction.removeExtra("arguments") - } - return transaction - } - }) -} -``` - ## Custom Telemetry in Compose Composable functions can run many times during recomposition. Don't send custom Sentry spans, messages, diff --git a/docs/platforms/android/integrations/navigation/index.mdx b/docs/platforms/android/integrations/navigation/index.mdx index 27bc2bbd49b0d2..d000dd0c1cba15 100644 --- a/docs/platforms/android/integrations/navigation/index.mdx +++ b/docs/platforms/android/integrations/navigation/index.mdx @@ -10,24 +10,36 @@ categories: The `sentry-android-navigation` and `sentry-android-navigation3` libraries provide support for Sentry's Android navigation instrumentation. Use them to automatically add breadcrumbs, track screen names, and start navigation transactions whenever users navigate around your app. -This page covers both: +This page covers: -- **Navigation 2** (`androidx.navigation`) via `SentryNavigationListener` -- **Navigation 3** (`androidx.navigation3`) via `SentryNavEffect` +- **[Navigation 2](https://developer.android.com/guide/navigation/)** (`androidx.navigation`) for classic Views and Jetpack Compose via `SentryNavigationListener` +- **[Navigation 3](https://developer.android.com/guide/navigation/navigation-3)** (`androidx.navigation3`) for Jetpack Compose via `SentryNavEffect` -If you're still using `NavController`, follow the Navigation 2 setup below. If you've moved to `NavDisplay`, skip to [Navigation 3](#navigation-3). +If you're using `NavController`, follow the Navigation 2 setup below. If you're using `NavDisplay`, skip to [Navigation 3](#navigation-3). ## Navigation 2 - +`SentryNavigationListener` for Navigation 2 integrations lets you observe destination changes reported by your `NavController`. Upon every destination change the listener: -If you're using Navigation 2 with Jetpack Compose, see Jetpack Compose Navigation instead. +- starts a new navigation transaction and binds it to the current [Sentry scope](https://docs.sentry.io/platforms/android/enriching-events/scopes/)† +- emits a breadcrumb +- updates the currently tracked screen name - +`SentryNavigationListener` can be used with: -### Install +- [Classic Views](#classic-views) +- [Jetpack Compose](#jetpack-compose) + + + † A new navigation transaction will *not* be bound if another unfinished + transaction is already bound to the current scope. + -Sentry captures data by adding a `NavController.OnDestinationChangedListener`. To add the Navigation integration, install the [Android SDK](/platforms/android/), then add the `sentry-android-navigation` dependency using Gradle: +### Classic Views + +#### Install + +Install the [Android SDK](/platforms/android/), then add the `sentry-android-navigation` dependency using Gradle: ```groovy {filename:build.gradle} implementation 'io.sentry:sentry-android:{{@inject packages.version('sentry.java.android', '6.2.0') }}' @@ -39,9 +51,9 @@ implementation("io.sentry:sentry-android:{{@inject packages.version('sentry.java implementation("io.sentry:sentry-android-navigation:{{@inject packages.version('sentry.java.android.navigation', '6.2.0') }}") ``` -### Configure +#### Configure -Configuration should happen in the respective lifecycle callbacks, once you retrieve your `NavController` instance: +Registration of the `SentryNavigationListener` should happen in the appropriate lifecycle callbacks of the entity that owns your `NavController`: ```kotlin import androidx.navigation.NavController @@ -88,11 +100,9 @@ protected void onPause() { } ``` -By default, the navigation transaction finishes automatically after it reaches the specified [idleTimeout](/platforms/android/configuration/options/#idleTimeout) and all of its child spans are finished. You can customize the timeout to your needs. +#### Verify -### Verify - -The snippet below includes a sample `Fragment` with a couple of navigation events and captures an intentional message, so you can test that everything is working as soon as you set it up: +The snippet below includes a sample `Fragment` with example navigation events. It captures an intentional message, so you can test that everything is working as soon as you set it up: ```kotlin import android.os.Bundle @@ -139,14 +149,206 @@ class HomeFragment : Fragment() { } ``` -### Customize the Recorded Breadcrumb/Transaction +### Jetpack Compose + +#### Auto-Installation with the Sentry Android Gradle Plugin + +If you're using the [Sentry Android Gradle Plugin](/platforms/android/configuration/gradle/), it will automatically register `SentryNavigationListener` with any `NavHostController`s you create via [`rememberNavController`](https://developer.android.com/reference/kotlin/androidx/navigation/compose/rememberNavController.composable). + + + +Be sure not to call Sentry's `withSentryObservableEffect` method (discussed [below](#configure-1)) on a `NavHostController` that the Sentry Android Gradle Plugin already auto-instruments. Doing so can register multiple `SentryNavigationListener`s and produce duplicate navigation data. + + + +##### Install + +Add the Sentry Android Gradle plugin in your `build.gradle` file: + +```groovy +plugins { + id "io.sentry.android.gradle" version "{{@inject packages.version('sentry.java.android.gradle-plugin', '3.0.0') }}" +} +``` + +```kotlin +plugins { + id("io.sentry.android.gradle") version "{{@inject packages.version('sentry.java.android.gradle-plugin', '3.0.0') }}" +} +``` + + + +Learn more about the Sentry Android Gradle plugin in our [Gradle](/platforms/android/configuration/gradle/) documentation. Details about auto-installation can be found in the [Auto Instrumentation](/platforms/android/configuration/gradle/#tracing-auto-instrumentation) section. + + + +##### Disable + +If you want to disable the plugin's automatic Compose instrumentation, including Navigation 2 instrumentation, add the following to your `build.gradle` file: + +```groovy +import java.util.EnumSet +import io.sentry.android.gradle.extensions.InstrumentationFeature + +sentry { + tracingInstrumentation { + enabled = true + features = EnumSet.allOf(InstrumentationFeature) - InstrumentationFeature.COMPOSE + } +} +``` + +```kotlin +import java.util.EnumSet +import io.sentry.android.gradle.extensions.InstrumentationFeature + +sentry { + tracingInstrumentation { + enabled.set(true) + features.set(EnumSet.allOf(InstrumentationFeature::class.java) - InstrumentationFeature.COMPOSE) + } +} +``` + +#### Manual Installation + +##### Install + +Sentry captures data via a `NavHostController.withSentryObservableEffect` extension function that registers a `SentryNavigationListener` under the hood. To use it, install the Android SDK, then add the `sentry-compose-android` dependency in Gradle: + +```groovy +implementation 'io.sentry:sentry-android:{{@inject packages.version('sentry.java.android', '6.2.0') }}' +implementation 'io.sentry:sentry-compose-android:{{@inject packages.version('sentry.java.compose.android', '6.2.0') }}' +``` + +```kotlin +implementation("io.sentry:sentry-android:{{@inject packages.version('sentry.java.android', '6.2.0') }}") +implementation("io.sentry:sentry-compose-android:{{@inject packages.version('sentry.java.compose.android', '6.2.0') }}") +``` + +##### Configure + +Configuration should happen in the `@Composable` function that owns your `NavHost`: + +```kotlin +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.rememberNavController +import io.sentry.compose.withSentryObservableEffect + +val navController = rememberNavController().withSentryObservableEffect( + enableNavigationBreadcrumbs = true, // enabled by default + enableNavigationTracing = true // enabled by default +) + +NavHost( + navController = navController +) { + ... +} +``` + +#### Verify + +This snippet includes a sample `Activity` with example navigation events between composables. It captures an intentional message, so you can test that everything is working as soon as you set it up: + +```kotlin +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController +import androidx.navigation.NavType +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import io.sentry.Sentry +import io.sentry.compose.withSentryObservableEffect + +class ComposeActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContent { + val navController = rememberNavController().withSentryObservableEffect() + SampleNavigation(navController) + } + } +} + +@Composable +fun SampleNavigation(navController: NavHostController) { + NavHost( + navController = navController, + startDestination = "first" + ) { + composable("first") { + First( + navigateToSecond = { navController.navigate("second") } + ) + } + composable("second") { + Second() + } + } +} + +@Composable +fun First( + navigateToSecond: () -> Unit +) { + Column( + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.fillMaxSize() + ) { + Button( + onClick = { navigateToSecond() }, + modifier = Modifier.padding(top = 32.dp) + ) { + Text("Navigate to Second") + } + Button( + onClick = { Sentry.captureMessage("Some message from Compose.") }, + modifier = Modifier.padding(top = 32.dp) + ) { + Text("Message from Compose") + } + } +} + +@Composable +fun Second() { + Column( + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.fillMaxSize() + ) { + Text("Second Screen") + } +} +``` + +### Scrub Sensitive Info from the Recorded Breadcrumb/Transaction + +`SentryNavigationListener` captures route arguments as additional data on breadcrumbs and transactions. If the arguments contain PII, you can strip them out with `BeforeBreadcrumbCallback` and `BeforeSendTransactionCallback`.† -By default, the Navigation integration captures route arguments as additional data on breadcrumbs and transactions. In case the arguments contain any PII data, you can strip it out by way of `BeforeBreadcrumbCallback` and `EventProcessor` respectively. To do that, [manually initialize](/platforms/android/manual-setup/#configuration-via-sentryoptions) the SDK and add the following snippet: +To do so, [manually initialize](/platforms/android/manual-setup/#configuration-via-sentryoptions) the SDK and add the following snippet: ```kotlin -import io.sentry.EventProcessor import io.sentry.android.core.SentryAndroid import io.sentry.SentryOptions.BeforeBreadcrumbCallback +import io.sentry.SentryOptions.BeforeSendTransactionCallback import io.sentry.android.navigation.SentryNavigationListener SentryAndroid.init(this) { options -> @@ -157,17 +359,25 @@ SentryAndroid.init(this) { options -> } breadcrumb } - options.addEventProcessor(object : EventProcessor { - override fun process(transaction: SentryTransaction, hint: Hint): SentryTransaction? { - if (SentryNavigationListener.NAVIGATION_OP == transaction.contexts.trace.operation) { - transaction.removeExtra("arguments") - } - return transaction + + options.beforeSendTransaction = BeforeSendTransactionCallback { transaction, _ -> + val trace = transaction.contexts.trace + if (SentryNavigationListener.NAVIGATION_OP == trace?.operation) { + trace.setData("arguments", null) } - }) + transaction + } } ``` + + † The snippet above removes route arguments, but it doesn't scrub route names. + Define routes with stable names and placeholders, such as `profile/{user_id}`, + and pass only sanitized values as arguments. Avoid putting PII directly in + route names, as they can appear in breadcrumb `from` and `to` fields, + transaction names, and screen names. + + ## Navigation 3 @@ -178,20 +388,23 @@ See the [Limitations](#limitations) section below for additional restrictions. -Android's [Navigation 3 library](https://developer.android.com/guide/navigation/navigation-3) expects apps to manage their own back stack and to push and pop entries in order to navigate. Apps pass their back stack to a `NavDisplay` and define corresponding composables. `NavDisplay` renders those composables to screen as the back stack entries change. - -`SentryNavEffect` instruments the back stack passed to `NavDisplay`. By default, every time the top of the back stack changes, `SentryNavEffect` will: +Android's [Navigation 3 library](https://developer.android.com/guide/navigation/navigation-3) expects apps to manage their own back stack and to push and pop entries in order to navigate. `SentryNavEffect` instruments the back stack passed to your `NavDisplay`. By default, every time the top of the back stack changes, `SentryNavEffect` will: -- start a new navigation transaction (and finish any prior navigation transaction) +- start a new navigation transaction and binds it to the current [Sentry scope](https://docs.sentry.io/platforms/android/enriching-events/scopes/)† - emit a breadcrumb - update the currently tracked screen name -- record the latest 10 entries from the back stack as event context +- record the latest 5 entries from the back stack as event context See [Customize Nav3 Options](#customize-nav3-options) to learn how to modify those defaults. + + † A new navigation transaction will *not* be started if another unfinished + transaction is already bound to the current scope. + + ### Install -Install the Android SDK and add Sentry's Navigation 3 library: +Install the Android SDK and add the `sentry-android-navigation3` library: ```groovy {filename:build.gradle} dependencies { @@ -221,11 +434,11 @@ import kotlinx.serialization.Serializable @Composable fun AppNavigation() { // Create your back stack like usual. - val backStack = rememberNavBackStack(Route.Home) + val backStack = rememberNavBackStack(Home) // Place SentryNavEffect in the same composable as your NavDisplay and call the // effect first. Provide a BackStackEntryMapper with the values you want to - // show up in Sentry. Be sure to omit PII and other sensitive info. + // show up in Sentry. Omit PII and other sensitive info. SentryNavEffect( backStack = backStack, backStackEntryMapper = { entry -> @@ -256,10 +469,9 @@ Values returned from `BackStackEntryMapper` are **not** scrubbed by the Sentry S - - Multiple, simultaneously active `SentryNavEffect` instances writing to the same [Sentry scope](https://docs.sentry.io/platforms/android/enriching-events/scopes/) are ***not*** supported. Violating this restriction can result in duplicated or interleaved data and undefined transaction behavior. +Multiple, simultaneously active `SentryNavEffect` instances writing to the same [Sentry scope](https://docs.sentry.io/platforms/android/enriching-events/scopes/) are **_not_** supported. Violating this restriction can result in duplicated or interleaved data and undefined transaction behavior. @@ -404,11 +616,11 @@ import kotlinx.serialization.Serializable @Serializable @SerialName("Home") -data class Home(userName: String) : NavKey +data class Home(val userName: String) : NavKey @Serializable @SerialName("ProductDetail") -data class ProductDetail(userName: String, productId: String) : NavKey +data class ProductDetail(val userName: String, val productId: String) : NavKey val backStackItemMapper = BackStackEntryMapper { entry -> when (entry) { @@ -424,9 +636,17 @@ val backStackItemMapper = BackStackEntryMapper { entry -> ### Limitations -`SentryNavEffect` treats the top entry in your back stack as the current screen. That works well for most Nav3 setups, but it means that `SentryNavEffect` does ***not***: +`SentryNavEffect` treats the top entry in your back stack as the current screen. That works well for most Nav3 setups, but it means that `SentryNavEffect` does **_not_**: - understand the concept of Nav3 [Scenes](https://developer.android.com/guide/navigation/navigation-3/scenes) or multi-pane layouts - track multiple back stacks - permit multiple, simultaneously active `SentryNavEffect` instances - make special accommodations for [predictive back](https://developer.android.com/guide/navigation/custom-back/predictive-back-gesture) gestures (e.g., spans produced by predictively rendered composables may appear under the current destination's transaction) + +## Navigation 2 and Navigation 3 Interoperability + +Navigation 2 and Navigation 3 can coexist in the same app. Their Sentry integrations observe navigation independently, but both write to the same Sentry scope by default. + +If both integrations observe the same navigation flow – for instance, a Nav2 destination hosts a Nav3 flow – Sentry can receive duplicate breadcrumbs or conflicting screen names and transactions. Choose one integration to report each flow, or configure the integrations so they don't report the same data to the same scope. + +If you're using the Sentry Android Gradle Plugin, be sure to account for automatically enabled Navigation 2 instrumentation when deciding which integration should report a flow. diff --git a/docs/platforms/dart/common/index.mdx b/docs/platforms/dart/common/index.mdx index 8cb3ec4aa923a4..a15ba542b8fb8e 100644 --- a/docs/platforms/dart/common/index.mdx +++ b/docs/platforms/dart/common/index.mdx @@ -24,24 +24,13 @@ This guide focuses on plain Dart. If you're building a Flutter app, use the dedi ## Install - - - - Add the Sentry Dart SDK to your `pubspec.yaml`: - - - ```yml {filename:pubspec.yaml} dependencies: sentry: ^{{@inject packages.version('sentry.dart') }} ``` - - - - ## Configure Choose the features you want to configure, and this guide will show you how: @@ -54,15 +43,8 @@ Choose the features you want to configure, and this guide will show you how: Configuration should happen as **early as possible** in your application's lifecycle. - - - - Import and initialize the SDK in your app's entry point: - - - ```dart import 'package:sentry/sentry.dart'; @@ -84,25 +66,14 @@ Future main() async { } ``` - - - - ## Verify Your Setup Let's test your setup and confirm that data reaches your Sentry project. ### Issues - - - - To verify that Sentry captures errors and creates issues in your Sentry project, add this intentional error to your application: - - - ```dart import 'package:sentry/sentry.dart'; @@ -116,10 +87,6 @@ try { } ``` - - - - diff --git a/docs/platforms/dart/common/tracing/streamed-spans/index.mdx b/docs/platforms/dart/common/tracing/streamed-spans/index.mdx index 01c455fadffc54..c0df776307acfd 100644 --- a/docs/platforms/dart/common/tracing/streamed-spans/index.mdx +++ b/docs/platforms/dart/common/tracing/streamed-spans/index.mdx @@ -67,23 +67,12 @@ Follow ___CURRENT_URL___ to migrate custom instrumentation and filtering to span ## Configuration - - - - Configure tracing with `tracesSampleRate` or `tracesSampler`. No additional lifecycle setting is required. - - - - - - - To opt out of span streaming, set `options.traceLifecycle = SentryTraceLifecycle.static`. Transaction mode supports `beforeSendTransaction` and `ignoreTransactions`; these options have no effect in stream mode. Use only the APIs for the tracing mode you choose. Calls to APIs from the other mode are ignored: @@ -122,15 +111,8 @@ The SDK instruments common operations for you, but you can wrap your own code in ### Start a Span - - - - Use `Sentry.startSpan` to create a span that ends automatically when the callback completes: - - - ```dart final result = await Sentry.startSpan( 'my-operation', @@ -144,16 +126,8 @@ final result = await Sentry.startSpan( ); ``` - - - - - Child spans created inside the callback are automatically associated with the parent through zones: - - - ```dart await Sentry.startSpan('parent-operation', (_) async { await Sentry.startSpan('child-step-1', (_) async { @@ -166,19 +140,11 @@ await Sentry.startSpan('parent-operation', (_) async { }); ``` - - - - - By default, a span inherits the currently active span as its parent. To change this, pass `parentSpan`: - `parentSpan: null` forces a service span with no local parent. - `parentSpan: someSpan` parents the new span under a specific span. - - - ```dart // force a new service span await Sentry.startSpan( @@ -210,44 +176,22 @@ try { } ``` - - - - #### Create Spans for Synchronous Work - - - - `Sentry.startSpan` takes an asynchronous callback (returning `Future`). For synchronous work, use `Sentry.startSpanSync`, which takes a synchronous callback (returning `T`). Both variants can be freely nested, and parent-child relationships resolve correctly across sync and async boundaries: - - - ```dart final config = Sentry.startSpanSync('parse-config', (_) { return Config.parse(raw); }); ``` - - - - If a span isn't sampled, the callback still runs and receives a no-op span, so all span operations remain safe to call. #### Create Spans That Outlive a Callback - - - - Use `Sentry.startInactiveSpan` when the work can't be wrapped in a single callback — widget lifecycles, stream subscriptions, or platform channel round-trips. You have to call `end()` manually, and other spans do **not** automatically become its children — to nest a span under it, pass it explicitly via `parentSpan` when starting the child. - - - ```dart final paymentSpan = Sentry.startInactiveSpan( 'payment', @@ -260,21 +204,10 @@ void onPaymentComplete() { } ``` - - - - #### Retroactively Set Span Timing - - - - When the real start or end of the work happened before you could create or end the span (for example, a duration measured by a platform channel) pass `startTimestamp` or an explicit `end` time: - - - ```dart // startTimestamp is available on the callback variants Sentry.startSpanSync('replay-import', (_) => importRows(), @@ -285,18 +218,10 @@ final paymentSpan = Sentry.startInactiveSpan('payment'); paymentSpan.end(endTimestamp: nativeEnd); ``` - - - - ## Add Attributes Attach structured metadata to spans using typed `SentryAttribute` values. - - - - You can set attributes when starting a span: @@ -305,9 +230,6 @@ Sentry automatically sets several standard attributes on spans. To avoid acciden - - - ```dart await Sentry.startSpan( 'process-order', @@ -323,16 +245,8 @@ await Sentry.startSpan( ); ``` - - - - - Or add them to an already running span with `setAttribute` or `setAttributes`. Use `removeAttribute` to remove an attribute: - - - ```dart await Sentry.startSpan('handle-request', (span) async { span.setAttribute( @@ -349,10 +263,6 @@ await Sentry.startSpan('handle-request', (span) async { }); ``` - - - - Each attribute value is created with a typed `SentryAttribute` factory: @@ -411,36 +321,18 @@ You can shape what ends up in Sentry by filtering span data or dropping spans en ### Filter Spans - - - - To modify or redact span data before it's sent, use `beforeSendSpan`: - - - ```dart options.beforeSendSpan = (span, hint) { span.removeAttribute('http.request.body'); }; ``` - - - - ### Drop Spans - - - - To prevent specific spans from being sent, use `ignoreSpans`. Rules are evaluated at span start and match against the span name. Attribute-based matching is not yet supported. - - - ```dart options.ignoreSpans = [ IgnoreSpanRule.nameEquals('health-check'), @@ -450,10 +342,6 @@ options.ignoreSpans = [ ]; ``` - - - - | Factory | Matches | @@ -471,15 +359,8 @@ When an ignored span has children, the children are re-parented to the nearest r If you use `tracesSampleRate`, no changes are needed — it works the same way in stream mode. - - - - If you use a custom `tracesSampler`, the shape of the sampling context is different in stream mode. Instead of a transaction context, read the span's `name` and `attributes` from `samplingContext.spanContext`: - - - ```dart options.tracesSampler = (samplingContext) { final spanContext = samplingContext.spanContext; @@ -490,10 +371,6 @@ options.tracesSampler = (samplingContext) { }; ``` - - - - Only service spans are sampled and child spans inherit the service span's decision. When a service span isn't sampled, its callback still executes with a no-op span, so all span operations remain safe to call. ## Distributed Tracing (Optional) diff --git a/docs/platforms/dart/guides/flutter/index.mdx b/docs/platforms/dart/guides/flutter/index.mdx index 7a590f8d3b7e60..236116b398d18e 100644 --- a/docs/platforms/dart/guides/flutter/index.mdx +++ b/docs/platforms/dart/guides/flutter/index.mdx @@ -21,15 +21,8 @@ categories: Sentry captures data by using an SDK within your application's runtime. - - - - We recommend installing the SDK through our [Sentry Wizard](https://github.com/getsentry/sentry-wizard). Run one of the following commands inside your project directory: - - - ```bash {tabTitle:brew} {mdExpandTabs} brew install getsentry/tools/sentry-wizard && sentry-wizard -i flutter ``` @@ -72,10 +65,6 @@ chmod +x sentry-wizard npx @sentry/wizard@latest -i flutter ``` - - - - This will patch your project and configure the SDK. You only need to patch the project once, then you can add the patched files to your version control system. If you prefer, you can also [set up the SDK manually](/platforms/dart/guides/flutter/manual-setup/). @@ -102,23 +91,12 @@ Let's test your setup and confirm that data reaches your Sentry project. ### Issues - - - - The wizard added a sample exception to `main.dart` that is captured when the app starts. Run your app to send it to Sentry: - - - ```bash flutter run ``` - - - - After you've confirmed the issue in Sentry, remove the sample exception from `main.dart` so it isn't captured on every launch. diff --git a/docs/platforms/dart/guides/flutter/manual-setup.mdx b/docs/platforms/dart/guides/flutter/manual-setup.mdx index 2e59542fe955a1..29fb4440898c64 100644 --- a/docs/platforms/dart/guides/flutter/manual-setup.mdx +++ b/docs/platforms/dart/guides/flutter/manual-setup.mdx @@ -12,24 +12,13 @@ If you can't (or prefer not to) run the [automatic setup](/platforms/dart/guides ## Install - - - - Add the Sentry Flutter SDK to your `pubspec.yaml`: - - - ```yml {filename:pubspec.yaml} dependencies: sentry_flutter: ^{{@inject packages.version('sentry.dart.flutter') }} ``` - - - - ### Apple Platform Setup The Flutter plugin installs the native Sentry SDK through Swift Package Manager. CocoaPods is not supported for this plugin. @@ -59,15 +48,8 @@ Choose the features you want to configure, and this guide will show you how: Configuration should happen as **early as possible** in your application's lifecycle. Logs and metrics are enabled by default; use `Sentry.logger` and `Sentry.metrics` after initialization without an enable flag. - - - - Import and initialize the SDK in your app's `main` function: - - - ```dart import 'package:flutter/widgets.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; @@ -102,25 +84,14 @@ Future main() async { } ``` - - - - ## Verify Your Setup Let's test your setup and confirm that data reaches your Sentry project. ### Issues - - - - To verify that Sentry captures errors and creates issues in your Sentry project, add this intentional error to your application: - - - ```dart import 'package:sentry_flutter/sentry_flutter.dart'; @@ -134,10 +105,6 @@ try { } ``` - - - - diff --git a/docs/platforms/dart/guides/flutter/troubleshooting.mdx b/docs/platforms/dart/guides/flutter/troubleshooting.mdx index ba0682d16c4710..b3cd8321cb8611 100644 --- a/docs/platforms/dart/guides/flutter/troubleshooting.mdx +++ b/docs/platforms/dart/guides/flutter/troubleshooting.mdx @@ -112,7 +112,7 @@ Source Context support requires compiling your app using the `split-debug-info` If you are using the Sentry Dart Plugin to upload [Debug Symbols](/platforms/dart/guides/flutter/debug-symbols/#automatically-upload-debug-symbols), refer to the points below to resolve potential issues. -A Sentry `auth_token` can be generated at the [Organization Tokens ](https://sentry.io/orgredirect/organizations/:orgslug/settings/auth-tokens/) settings page. +A Sentry auth token can be generated at the [Organization Tokens](https://sentry.io/orgredirect/organizations/:orgslug/settings/auth-tokens/) settings page. Make sure it's available to the plugin through the `SENTRY_AUTH_TOKEN` environment variable. Dart's `--obfuscate` option is required to be paired with `--split-debug-info` to generate a symbol map. See [Dart docs](https://github.com/flutter/flutter/wiki/Obfuscating-Dart-Code) for more information. diff --git a/docs/platforms/dotnet/guides/azure-functions-worker/index.mdx b/docs/platforms/dotnet/guides/azure-functions-worker/index.mdx index b70a17997070fb..a26ea50fc8845f 100644 --- a/docs/platforms/dotnet/guides/azure-functions-worker/index.mdx +++ b/docs/platforms/dotnet/guides/azure-functions-worker/index.mdx @@ -4,11 +4,11 @@ sdk: sentry.dotnet.azure.functions.worker description: "Learn about Sentry's .NET integration with Azure Functions." --- -Sentry provides an integration with Azure Functions through the [Sentry.Extensions.Logging](https://www.nuget.org/packages/Sentry.Extensions.Logging) and [Sentry.OpenTelemetry](https://www.nuget.org/packages/Sentry.OpenTelemetry) NuGet packages. +Sentry provides an integration with Azure Functions through the [Sentry.Extensions.Logging](https://www.nuget.org/packages/Sentry.Extensions.Logging) and [Sentry.OpenTelemetry.Exporter](https://www.nuget.org/packages/Sentry.OpenTelemetry.Exporter) NuGet packages. ## Features -In addition to capturing errors, you can monitor interactions between multiple services or applications by [enabling tracing](/concepts/key-terms/tracing/). +In addition to capturing errors, you can monitor interactions between multiple services or applications by enabling tracing. Select which Sentry features you'd like to install in addition to Error Monitoring to get the corresponding installation and configuration instructions below. @@ -21,8 +21,7 @@ Add the Sentry dependencies to your Azure Functions application: ```shell {tabTitle:.NET Core CLI} dotnet add package Sentry.Extensions.Logging -v {{@inject packages.version('sentry.dotnet.extensions.logging') }} // ___PRODUCT_OPTION_START___ performance -dotnet add package Sentry.OpenTelemetry -v {{@inject packages.version('sentry.dotnet.opentelemetry') }} -dotnet add package OpenTelemetry +dotnet add package Sentry.OpenTelemetry.Exporter -v {{@inject packages.version('sentry.dotnet') }} dotnet add package OpenTelemetry.Extensions.Hosting dotnet add package OpenTelemetry.Instrumentation.Http @@ -32,7 +31,9 @@ dotnet add package OpenTelemetry.Instrumentation.Http ```powershell {tabTitle:Package Manager} Install-Package Sentry.Extensions.Logging -Version {{@inject packages.version('sentry.dotnet.extensions.logging') }} // ___PRODUCT_OPTION_START___ performance -Install-Package Sentry.OpenTelemetry -Version {{@inject packages.version('sentry.dotnet.opentelemetry') }} +Install-Package Sentry.OpenTelemetry.Exporter -Version {{@inject packages.version('sentry.dotnet') }} +Install-Package OpenTelemetry.Extensions.Hosting +Install-Package OpenTelemetry.Instrumentation.Http // ___PRODUCT_OPTION_END___ ``` @@ -43,7 +44,7 @@ The [Sentry.Extensions.Logging](/platforms/dotnet/guides/extensions-logging/) pa The core features of Sentry are enabled by calling `AddSentry` when configuring logging. -Performance tracing can be enabled by adding Sentry to the OpenTelemetry `TracerProviderBuilder` and then configuring Sentry itself to use OpenTelemetry. +To enable tracing, add Sentry's OTLP exporter to the OpenTelemetry `TracerProviderBuilder` and call `UseOtlp()` on the Sentry options. See OpenTelemetry (OTLP) for sampling and trace propagation. For example: @@ -51,11 +52,10 @@ For example: ```csharp using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using OpenTelemetry; // ___PRODUCT_OPTION_START___ performance +using Microsoft.Extensions.DependencyInjection; using OpenTelemetry.Trace; // ___PRODUCT_OPTION_END___ -using Sentry.OpenTelemetry; var host = new HostBuilder() .ConfigureFunctionsWorkerDefaults() @@ -65,7 +65,7 @@ var host = new HostBuilder() services.AddOpenTelemetry().WithTracing(builder => { builder - .AddSentry() // <-- Configure OpenTelemetry to send traces to Sentry + .AddSentryOtlpExporter("___PUBLIC_DSN___") // <-- Send traces to Sentry over OTLP .AddHttpClientInstrumentation(); // From OpenTelemetry.Instrumentation.Http, instruments outgoing HTTP requests }); }) @@ -76,16 +76,13 @@ var host = new HostBuilder() { options.Dsn = "___PUBLIC_DSN___"; // ___PRODUCT_OPTION_START___ performance - options.TracesSampleRate = 1.0; - options.UseOpenTelemetry(); // <-- Configure Sentry to use open telemetry - options.DisableSentryHttpMessageHandler = true; // So Sentry doesn't also create spans for outbound HTTP requests + options.UseOtlp(); // <-- Configure Sentry to use OpenTelemetry for tracing // ___PRODUCT_OPTION_END___ options.Debug = true; }); }) .Build(); - await host.RunAsync(); ``` diff --git a/docs/platforms/java/common/tracing/instrumentation/okhttp.mdx b/docs/platforms/java/common/tracing/instrumentation/okhttp.mdx index aea6f2b70f048a..28652ca30f578f 100644 --- a/docs/platforms/java/common/tracing/instrumentation/okhttp.mdx +++ b/docs/platforms/java/common/tracing/instrumentation/okhttp.mdx @@ -41,7 +41,45 @@ For other dependency managers, see the [central Maven repository](https://search ## Configure -Configuration should happen once you create your `OkHttpClient` instance. + + +### Configure Spring Boot Automatically + +Sentry's Spring Boot 2, 3, and 4 integrations automatically instrument every `OkHttpClient` bean managed by Spring when you enable this option. Install `sentry-okhttp`, configure `sentry.dsn`, and enable the integration in your application configuration: + +```properties {tabTitle:application.properties} {filename:src/main/resources/application.properties} +sentry.clients.ok-http-enabled=true +``` + +```yaml {tabTitle:application.yml} {filename:src/main/resources/application.yml} +sentry: + clients: + ok-http-enabled: true +``` + +The auto-configuration preserves each client's existing configuration, interceptors, and event listeners. It adds the Sentry interceptor only once and doesn't create an `OkHttpClient` bean if your application hasn't defined one. + +Auto-configured clients use a `SentryOkHttpInterceptor` and `SentryOkHttpEventListener` with default options. To customize them (for example, with a `BeforeSpanCallback`, the `captureFailedRequests` options, or a delegate `EventListener` as described below), add your own configured `SentryOkHttpInterceptor` or `SentryOkHttpEventListener` to the bean. The auto-configuration uses your instances instead of adding its own. + +Auto-configuration doesn't instrument clients created outside Spring or `OkHttpClient` subclasses. Configure these clients manually as shown below. + + + +Sentry skips auto-configuration when the OpenTelemetry Java Agent is on the classpath because the agent already instruments OkHttp. + + + +### Configure Manually + +Add the Sentry interceptor and event listener when you create an OkHttp client that Spring doesn't manage. + + + + + +Add the Sentry interceptor and event listener when you create your `OkHttpClient` instance. + + ```kotlin import okhttp3.OkHttpClient diff --git a/docs/platforms/javascript/common/configuration/integrations/vercelai.mdx b/docs/platforms/javascript/common/configuration/integrations/vercelai.mdx index f12e105eb13428..8f5d5f7a68e213 100644 --- a/docs/platforms/javascript/common/configuration/integrations/vercelai.mdx +++ b/docs/platforms/javascript/common/configuration/integrations/vercelai.mdx @@ -49,8 +49,8 @@ By default, tracing support is added to the following `ai` functions: - `generateText()` - `streamText()` -- `generateObject()` -- `streamObject()` +- `generateObject()` — on AI SDK v6 and below +- `streamObject()` — on AI SDK v6 and below - `embed()` - `embedMany()` - `rerank()` @@ -58,6 +58,23 @@ By default, tracing support is added to the following `ai` functions: Plus `generate()` and `stream()` on [`ToolLoopAgent`](https://ai-sdk.dev/docs/agents/overview#toolloopagent-class). + + +On AI SDK v7, `generateObject()` and `streamObject()` don't produce spans. The AI SDK deprecated both in v6 and doesn't emit telemetry events for them in v7. Use `generateText()` or `streamText()` with an `output` setting instead, which Sentry traces like any other call. The [AI SDK migration guide](https://ai-sdk.dev/docs/migration-guides/migration-guide-6-0) covers the change. + +```javascript +import { generateText, Output } from "ai"; +import { z } from "zod"; + +const { output } = await generateText({ + model, + output: Output.object({ schema: z.object({ name: z.string() }) }), + prompt: "Return a city name", +}); +``` + + + ## Trace Jev Decisions With Sentry SDK `11.7.0` or higher and AI SDK `7.0.128` or higher, `vercelAIIntegration` automatically traces `experimental_decide()` calls, including calls to TypeSafe's Jev model through Vercel AI Gateway. Keep your existing Sentry setup with tracing enabled; no additional integration or telemetry registration is needed. diff --git a/docs/platforms/javascript/common/data-management/data-collected/index__v10.x.mdx b/docs/platforms/javascript/common/data-management/data-collected/index__v10.x.mdx index cdc7c4732d7ed8..160e8712ffe7f5 100644 --- a/docs/platforms/javascript/common/data-management/data-collected/index__v10.x.mdx +++ b/docs/platforms/javascript/common/data-management/data-collected/index__v10.x.mdx @@ -147,14 +147,14 @@ The SDK may still send the response body size, taken from the `content-length` h By default, SDKs set up by the Sentry CLI Wizard (`@sentry/wizard`) will enable uploading source maps to Sentry. -To disable source map upload, see the Source Maps documentation. +To disable source map upload, see the Source Maps documentation. ## Local Variables In Stack Trace The Sentry SDK does not send local variables in the error stack trace in client-side JavaScript SDKs. - You can enable sending local variables by setting `includeLocalVariables: true` in the `Sentry.init()` call. This activates the Local Variables Integration. The integration is added by default in Node.js-based runtimes. + You can enable sending local variables by setting `includeLocalVariables: true` in the `Sentry.init()` call. This activates the Local Variables Integration. The integration is added by default in Node.js-based runtimes. ## Device, Browser, OS and Runtime Information @@ -170,9 +170,9 @@ By default, the Sentry SDK sends information about the device and runtime to Sen The Sentry Electron SDK collects information about the device, such as the platform, architecture, available memory and version and build of your operating system or Linux distribution. - By default, the Additional Context Integration collects dimensions and resolution of the device screen. It can optionally collect the device's manufacturer and model name if the `deviceModelManufacturer` option is enabled. + By default, the Additional Context Integration collects dimensions and resolution of the device screen. It can optionally collect the device's manufacturer and model name if the `deviceModelManufacturer` option is enabled. - By default, the GPU Context Integration collects GPU information. It can optionally collect more detailed information if the `infoLevel` option is set to `complete`. + By default, the GPU Context Integration collects GPU information. It can optionally collect more detailed information if the `infoLevel` option is set to `complete`. diff --git a/docs/platforms/javascript/common/logs/index.mdx b/docs/platforms/javascript/common/logs/index.mdx index e423e3f1fd1460..8b0c66648def51 100644 --- a/docs/platforms/javascript/common/logs/index.mdx +++ b/docs/platforms/javascript/common/logs/index.mdx @@ -14,18 +14,10 @@ Sentry Logs are **high-cardinality** — you can pass any attributes you want an - - - - - ## Setup Logs are enabled by default. Just initialize the SDK and use `Sentry.logger` to send logs. - - - ```javascript @@ -48,12 +40,6 @@ export default defineCloudflareOptions((env) => ({ - - - - - - ## Send Logs Use `Sentry.logger` to send logs at different levels. A log message is required for Sentry to send the log. @@ -67,9 +53,6 @@ Use `Sentry.logger` to send logs at different levels. A log message is required | `error` | Failures that need attention | | `fatal` | Critical failures, system down | - - - ```javascript Sentry.logger.trace("Entering function", { fn: "processOrder" }); Sentry.logger.debug("Cache lookup", { key: "user:123" }); @@ -79,21 +62,12 @@ Sentry.logger.error("Payment failed", { reason: "card_declined" }); Sentry.logger.fatal("Database unavailable", { host: "primary" }); ``` - - - - - - ## Add Context Pass structured data as the second argument — these attributes become searchable columns in Sentry. Use `Sentry.logger.fmt` for parameterized messages. Values are automatically extracted as searchable attributes. - - - ```javascript // Pass attributes directly Sentry.logger.info("User signed up", { @@ -108,12 +82,6 @@ const productName = "Widget Pro"; Sentry.logger.info(Sentry.logger.fmt`User ${userId} purchased ${productName}`); ``` - - - - - - ## Shared Attributes @@ -124,9 +92,6 @@ To attach attributes to a broader or narrower context, set them on a specific sc See Attributes for more information. - - - ```javascript // Applied to all logs and metrics Sentry.setAttributes({ @@ -148,12 +113,6 @@ Sentry.withScope((scope) => { }); ``` - - - - - - ## Console Integration Already using `console.log`? Capture console calls as Sentry Logs with `consoleLoggingIntegration`. @@ -162,9 +121,6 @@ Multiple arguments are parsed as searchable attributes (requires SDK `10.13.0`+) For [Consola](https://github.com/unjs/consola) users, use `Sentry.createConsolaReporter()` instead (requires SDK `10.12.0`+). - - - ```javascript @@ -206,21 +162,12 @@ export default defineCloudflareOptions((env) => ({ - - - - - - ## Filter Logs Use `beforeSendLog` to filter or modify logs before they're sent. Return `null` to drop a log. The log object includes: `level`, `message`, `timestamp`, and `attributes`. - - - ```javascript @@ -269,11 +216,6 @@ export default defineCloudflareOptions((env) => ({ - - - - - ## How Logs Link to Other Features Everything in Sentry is linked by trace. When you're viewing a log, you can jump to the parent trace to see the full request context. When you're viewing a trace, you can see all logs emitted during that operation. This connection makes it easy to move between high-level performance data and detailed diagnostic logs. diff --git a/docs/platforms/javascript/common/session-replay/index.mdx b/docs/platforms/javascript/common/session-replay/index.mdx index 84f865183e6bef..f3229d5070955e 100644 --- a/docs/platforms/javascript/common/session-replay/index.mdx +++ b/docs/platforms/javascript/common/session-replay/index.mdx @@ -72,35 +72,18 @@ Session Replay only runs in the browser, so you only need to configure it in `in There is currently no PII scrubbing in canvas recordings! - - - - - #### Enable Canvas Recording Add `replayCanvasIntegration()` to record HTML canvas elements. This is opt-in and tree-shaken from your bundle if not used. - - - - - - - - - #### 3D and WebGL Canvases For 3D/WebGL canvases, the integration needs `preserveDrawingBuffer` to export images, which can affect performance. To avoid this, enable manual snapshotting and call `snapshot()` inside your paint loop. Call `snapshot()` in the same execution loop as draw commands to avoid capturing empty buffers. - - - ```javascript // Step 1: Enable manual snapshotting Sentry.replayCanvasIntegration({ @@ -116,19 +99,10 @@ function paint() { } ``` - - - - - - #### WebGPU Canvases WebGPU canvas textures expire after the current task completes. Use `skipRequestAnimationFrame: true` to capture immediately after rendering. - - - ```javascript // Step 1: Enable manual snapshotting Sentry.replayCanvasIntegration({ @@ -150,19 +124,10 @@ function paint() { } ``` - - - - ### Content Security Policy (CSP) - - - - - #### Configure CSP for Replay Session Replay uses a WebWorker for compression off the main UI thread. Add these CSP entries to allow workers to load. @@ -173,19 +138,11 @@ Safari versions ≤ 15.4 also need `child-src`. - - - ```text worker-src 'self' blob: child-src 'self' blob: ``` - - - - - If you're unable to update your CSP policy to allow inline web workers, you can also [use a custom compression worker](./configuration/#using-a-custom-compression-worker) instead. @@ -216,11 +173,6 @@ If you prefer not to record an entire session, you can elect to capture a replay Sampling controls how much traffic results in a Session Replay. - - - - - #### Configure Sample Rates - - Percentage of sessions to record fully @@ -240,9 +192,6 @@ Sampling controls how much traffic results in a Session Replay. - - - ```javascript {filename:instrumentation-client.ts} Sentry.init({ dsn: "___PUBLIC_DSN___", @@ -257,11 +206,6 @@ Sentry.init({ }); ``` - - - - - ### How Sampling Works Sampling begins as soon as a session starts. When someone visits your application, sampling decisions happen in this order: diff --git a/docs/platforms/javascript/common/tracing/streamed-spans/index__v10.x.mdx b/docs/platforms/javascript/common/tracing/streamed-spans/index__v10.x.mdx index b11a53698d8668..6f05a18b2ab64c 100644 --- a/docs/platforms/javascript/common/tracing/streamed-spans/index__v10.x.mdx +++ b/docs/platforms/javascript/common/tracing/streamed-spans/index__v10.x.mdx @@ -100,15 +100,8 @@ Each flush sends only the spans accumulated since the last flush, grouped into e ### Start a Span - - - - Use `Sentry.startSpan()` to create a span that is automatically ended when the callback completes: - - - ```javascript const result = await Sentry.startSpan( { name: "my-operation", attributes: { "my.attribute": "value" } }, @@ -119,17 +112,8 @@ const result = await Sentry.startSpan( ); ``` - - - - - - Child spans created inside the callback are automatically associated with the parent: - - - ```javascript await Sentry.startSpan({ name: "parent-operation" }, async () => { await Sentry.startSpan({ name: "child-step-1" }, async () => { @@ -142,25 +126,14 @@ await Sentry.startSpan({ name: "parent-operation" }, async () => { }); ``` - - - - For more details on span creation APIs, such as `startSpan`, `startSpanManual`, or `startInactiveSpan`, see Instrumentation. ## Add Attributes Attach structured metadata to spans using `attributes`, which can be `string`, `number`, or `boolean`, as well as arrays of these types. - - - - You can set attributes when starting a span: - - - ```javascript Sentry.startSpan( { @@ -178,17 +151,8 @@ Sentry.startSpan( ); ``` - - - - - - Or add them to an already running span: - - - ```javascript Sentry.startSpan({ name: "handle-request" }, (span) => { // Set a single attribute @@ -202,13 +166,8 @@ Sentry.startSpan({ name: "handle-request" }, (span) => { }); ``` - - - For examples, see Adding Span Attributes. - - ### Shared Attributes Previously, transaction mode applied shared tags (`Sentry.setTag(s)`) to the service span (transaction). @@ -217,10 +176,6 @@ Set shared attributes on a specific scope instead. You don't need to remove tags from your code, since they still apply to errors. Instead, add attributes for all data that's relevant for spans, logs metrics. - - - - Use `Sentry.setAttribute` and `Sentry.setAttributes` to attach attributes that are automatically included in all spans (as well as your logs and metrics). These work just like `Sentry.setTag` and `Sentry.setTags`, but they accept `string`, `number`, and `boolean` values. @@ -228,9 +183,6 @@ To attach attributes to a broader or narrower context, set them on a specific sc See Attributes for more information. - - - ```javascript // Applied to all spans, logs and metrics Sentry.setAttributes({ @@ -252,10 +204,6 @@ Sentry.withScope((scope) => { }); ``` - - - - ## Breadcrumbs In stream mode, breadcrumbs are no longer sent with spans. @@ -265,10 +213,6 @@ They remain attached to errors, so you don't need to change how you record them. ### Filter Spans - - - - To modify or redact span data before it's sent, use `beforeSendSpan`. In stream mode, wrap it with `Sentry.withStreamedSpan()` so the SDK applies it to spans as they are flushed rather than only at transaction time. @@ -278,9 +222,6 @@ To modify or redact span data before it's sent, use - - ```JavaScript @@ -327,10 +268,6 @@ Sentry.init({ - - - - If you're using `beforeSendSpan`, wrap it with `Sentry.withStreamedSpan()` as shown above, otherwise the SDK falls back to transaction mode. @@ -353,15 +290,8 @@ If you're using `beforeSendTransaction` to drop spans, use [`ignoreSpans`](#drop In stream mode, `ignoreSpans` is evaluated at span start, so only the span name and attributes available at that point are taken into account. Any name updates or additional attributes added while the span is active won't influence whether the span is dropped. - - - - To prevent specific spans from being created, use the `ignoreSpans` option: - - - ```javascript @@ -419,10 +349,6 @@ Sentry.init({ - - - - If a matching span is a service span, all of its child spans are dropped as well. If a child span matches, only that span is dropped and its children are reparented to the nearest ancestor. diff --git a/docs/platforms/javascript/guides/angular/index.mdx b/docs/platforms/javascript/guides/angular/index.mdx index 6416ff0e830b94..a16215e9b8f881 100644 --- a/docs/platforms/javascript/guides/angular/index.mdx +++ b/docs/platforms/javascript/guides/angular/index.mdx @@ -25,24 +25,12 @@ at least Angular 17. ## Install - - - - Run the Sentry wizard to automatically configure Sentry in your Angular application. It will then guide you through the setup process, asking you to enable additional (optional) Sentry features for your application beyond error monitoring. - - - - ```bash npx @sentry/wizard@latest -i angular ``` - - - - This guide assumes that you enable all features and allow the wizard to add an example component to your application. You can add or remove features at any time, but setting them up now will save you the effort of configuring them manually later. diff --git a/docs/platforms/javascript/guides/angular/manual-setup.mdx b/docs/platforms/javascript/guides/angular/manual-setup.mdx index 9f04c928e159c8..e191d042612c73 100644 --- a/docs/platforms/javascript/guides/angular/manual-setup.mdx +++ b/docs/platforms/javascript/guides/angular/manual-setup.mdx @@ -23,20 +23,10 @@ You need: ## Install - - - - - - Run the command for your preferred package manager to add the Sentry SDK to your application. If you're updating your Sentry SDK to the latest version, check out our migration guide to learn more about breaking changes. - - - - ```bash {tabTitle:npm} npm install @sentry/angular --save ``` @@ -49,10 +39,6 @@ yarn add @sentry/angular pnpm add @sentry/angular ``` - - - - In its current major version, the Sentry Angular SDK supports Angular 14 and newer. @@ -94,18 +80,8 @@ Choose the features you want to configure, and this guide will show you how: ### Initialize the SDK - - - - - - The main configuration should happen as early as possible in your app's lifecycle. Typically that means in your `main.ts` file. - - - - ```typescript {tabTitle: App Config} {mdExpandTabs} {filename: main.ts} {5-41} import { bootstrapApplication } from "@angular/platform-browser"; import { appConfig } from "./app/app.config"; @@ -219,18 +195,8 @@ platformBrowserDynamic() .catch((err) => console.error(err)); ``` - - - - ### Register Sentry Providers - - - - - - The Sentry Angular SDK exports a couple of Angular providers that are necessary to fully instrument your application. We recommend registering them in your `app.config.ts` or main `app.module.ts`: @@ -239,10 +205,6 @@ If your Angular app is configured for SSR, make sure that the Sentry providers a - - - - ```typescript {tabTitle: App Config (Angular 19+)} {mdExpandTabs} {filename: app.config.ts} {9, 14-25} import { ApplicationConfig, @@ -338,10 +300,6 @@ import * as Sentry from "@sentry/angular"; export class AppModule {} ``` - - - - @@ -379,10 +337,6 @@ Let's test your setup and confirm that Sentry is working correctly and sending d ### Issues - - - - To verify that Sentry captures errors and creates issues in your Sentry project, add the following test button to one of your components (e.g. `app.component.ts`), which will trigger an error that Sentry will capture when you click it. @@ -391,10 +345,6 @@ To verify that Sentry captures errors and creates issues in your Sentry project, - - - - ```javascript {filename: app.component.ts} {5, 9-11} @Component({ selector: "app-root", @@ -410,25 +360,13 @@ class AppComponent { } ``` - - - - ### Tracing - - - - To test your tracing configuration, update the previous code snippet to start a trace to measure the time it takes to execute your code. Open the page in a browser and click the button to trigger a frontend error and performance trace. - - - - ```javascript {filename: app.component.ts} {10-11, 13-14} @Component({ selector: "app-root", @@ -448,10 +386,6 @@ class AppComponent { } ``` - - - - diff --git a/docs/platforms/javascript/guides/azure-functions/index.mdx b/docs/platforms/javascript/guides/azure-functions/index.mdx index c15efbdf34fbc7..731574513496e4 100644 --- a/docs/platforms/javascript/guides/azure-functions/index.mdx +++ b/docs/platforms/javascript/guides/azure-functions/index.mdx @@ -25,32 +25,14 @@ Choose the features you want to configure, and this guide will show you how: ### Install the Sentry SDK - - - - Run the command for your preferred package manager to add `@sentry/node` as a runtime dependency to your application: - - - - - - - ## Configure - - - - Make sure to initialize Sentry at the top of your function file before importing any other modules: - - - ```javascript {tabTitle:async} const Sentry = require("@sentry/node"); // ___PRODUCT_OPTION_START___ profiling @@ -85,21 +67,10 @@ Sentry.init({ // your function code ``` - - - - ### Capture Errors - - - - Because Azure Functions are short-lived, you have to explicitly `flush` Sentry events after calling `captureException`, or they may be lost before being sent to Sentry. - - - ```javascript {tabTitle:async} const Sentry = require("@sentry/node"); @@ -121,10 +92,6 @@ module.exports = async function (context, req) { }; ``` - - - - ### Add Readable Stack Traces With Source Maps (Optional) @@ -139,15 +106,8 @@ Let's test your setup and confirm that Sentry is working correctly and sending d ### Issues - - - - Let's verify that Sentry captures errors and creates issues in your Sentry project. Add an intentional error in your function: - - - ```javascript {tabTitle:async} const Sentry = require("@sentry/node"); @@ -172,21 +132,11 @@ module.exports = async function (context, req) { }; ``` - - - - ### Tracing - - - To test tracing, update your function to include a custom span: - - - ```javascript {tabTitle:async} const Sentry = require("@sentry/node"); @@ -206,10 +156,6 @@ module.exports = async function (context, req) { }; ``` - - - - diff --git a/docs/platforms/javascript/guides/bun/index.mdx b/docs/platforms/javascript/guides/bun/index.mdx index d70ce4d8aa9aca..ba7b0ba8e49a6b 100644 --- a/docs/platforms/javascript/guides/bun/index.mdx +++ b/docs/platforms/javascript/guides/bun/index.mdx @@ -23,37 +23,19 @@ Choose the features you want to configure, and this guide will show you how: ### Install the SDK - - - - Use the Bun package manager to add the Sentry SDK to your application: - - - ```bash {tabTitle:Bun} bun add @sentry/bun ``` - - - - ## Configure ### Initialize the Sentry SDK - - - - Sentry should be initialized as early in your app as possible. Create a file named `instrument.js` in the root directory of your project and add the following code: - - - ```javascript {filename: instrument.js} import * as Sentry from "@sentry/bun"; @@ -73,23 +55,12 @@ Sentry.init({ }); ``` - - - - ### Build With the Sentry Plugin (Recommended) - - - - We recommend building with the Sentry plugin, because it adds spans from your dependencies, such as database drivers, AI SDKs, and web frameworks like Express, Koa and Hapi. Bun has no runtime hook Sentry can use to instrument those packages, so the plugin rewrites them as `bun build` bundles them. Add `sentryBunPlugin` from `@sentry/bun/plugin` to your `Bun.build()` call, then run the output the same way, with `--preload`. Errors, the spans you create yourself, and `Bun.serve`, `node:http` and `fetch` spans work either way. - - - ```typescript {filename:build.ts} import { sentryBunPlugin } from "@sentry/bun/plugin"; @@ -101,21 +72,10 @@ await Bun.build({ }); ``` - - - - ### Apply Instrumentation to Your App - - - - Preload your instrumentation file with the [`--preload`](https://bun.com/docs/runtime#param-preload) flag. This is what guarantees that `Sentry.init()` runs before any other module is loaded. - - - ```bash {tabTitle:From source} bun --preload ./instrument.js app.js ``` @@ -124,10 +84,6 @@ bun --preload ./instrument.js app.js bun --preload ./instrument.js dist/app.js ``` - - - - ### Add Readable Stack Traces With Source Maps (Optional) @@ -142,15 +98,8 @@ Let's test your setup and confirm that Sentry is working correctly and sending d ### Issues - - - - First, let's verify that Sentry captures errors and creates issues in your Sentry project. Add the following code snippet to your main application file, which will call an undefined function, triggering an error that Sentry will capture: - - - ```javascript setTimeout(() => { try { @@ -161,22 +110,11 @@ setTimeout(() => { }, 99); ``` - - - - ### Tracing - - - - To test your tracing configuration, update the previous code snippet by starting a trace to measure the time it takes for the execution of your code: - - - ```javascript Sentry.startSpan( { @@ -195,10 +133,6 @@ Sentry.startSpan( ); ``` - - - - diff --git a/docs/platforms/javascript/guides/capacitor/index.mdx b/docs/platforms/javascript/guides/capacitor/index.mdx index e80630e6733c3c..7b8dab639d01e6 100644 --- a/docs/platforms/javascript/guides/capacitor/index.mdx +++ b/docs/platforms/javascript/guides/capacitor/index.mdx @@ -22,21 +22,10 @@ This guide will show you setup instructions for Angular, React, Vue, and Nuxt. I ### Install the Sentry SDK - - - - Run the command for your preferred package manager to add Sentry's Capacitor SDK and the SDK for the framework you're using to your application: - - - - - - - #### Angular @@ -74,23 +63,12 @@ Choose the features you want to configure, and this guide will show you how: ### Initialize the Sentry SDK - - - - Initialize Sentry as early as possible in your application's lifecycle. If you're using Angular, React, Vue, or Nuxt, make sure to forward the `init` method from the framework's Sentry SDK, as you can see in these code snippets. If you're following the vanilla setup, you don't need to do this. - - - - - - - ### Add Readable Stack Traces With Source Maps (Optional) @@ -109,10 +87,6 @@ Let's test your setup and confirm that Sentry is working correctly and sending d ### Issues - - - - To verify that Sentry captures errors and creates issues in your Sentry project, add the following test button and logic. @@ -121,9 +95,6 @@ To verify that Sentry captures errors and creates issues in your Sentry project, - - - ```javascript {tabTitle: Angular 12, 13, 14+} {mdExpandTabs} @Component({ selector: "app-root", @@ -187,24 +158,13 @@ export default { ``` - - - - ### Tracing - - - - To test your tracing configuration, update the previous code snippet and wrap the error in a custom span. Then, open the page in a browser and click the button to trigger a frontend error and trace. - - - ```javascript {tabTitle: Angular 12, 13, 14+} {mdExpandTabs} import * as Sentry from "@sentry/capacitor"; @@ -292,10 +252,6 @@ export default { ``` - - - - diff --git a/docs/platforms/javascript/guides/cloudflare/features/pages.mdx b/docs/platforms/javascript/guides/cloudflare/features/pages.mdx index 1815e5364ca64f..b750335e57c4cc 100644 --- a/docs/platforms/javascript/guides/cloudflare/features/pages.mdx +++ b/docs/platforms/javascript/guides/cloudflare/features/pages.mdx @@ -28,17 +28,10 @@ Cloudflare Pages applications are instrumented with the `sentryPagesPlugin` midd ### Add the Middleware - - - - To use the Sentry SDK, add the `sentryPagesPlugin` as [middleware to your Cloudflare Pages application](https://developers.cloudflare.com/pages/functions/middleware/). - - - ```javascript {filename:functions/_middleware.js} import * as Sentry from "@sentry/cloudflare"; @@ -56,20 +49,10 @@ export const onRequest = [ ]; ``` - - - - - - - If you don't have access to the `onRequest` middleware API, you can use the `wrapRequestHandler` API instead. For example: - - - ```javascript // hooks.server.js import { wrapRequestHandler } from "@sentry/cloudflare/request"; @@ -87,10 +70,6 @@ export const handle = ({ event, resolve }) => { }; ``` - - - - ## Control the Data You Send to Sentry (Optional) @@ -115,25 +94,14 @@ For the full list of categories and their defaults, see the - - - To test your tracing configuration, start a span around the failing code: ```javascript {filename:debug-sentry.js} diff --git a/docs/platforms/javascript/guides/cloudflare/frameworks/astro.mdx b/docs/platforms/javascript/guides/cloudflare/frameworks/astro.mdx index d409e432b6b51c..bd7fec2cc79440 100644 --- a/docs/platforms/javascript/guides/cloudflare/frameworks/astro.mdx +++ b/docs/platforms/javascript/guides/cloudflare/frameworks/astro.mdx @@ -36,18 +36,10 @@ The SDK reads standard Sentry environment variables including `SENTRY_DSN`, `SEN - - For Cloudflare Pages, you need to manually set up the `@sentry/cloudflare` SDK using the Pages middleware. - - - 1. Install both SDKs: - - - ```bash {tabTitle:npm} npm install @sentry/astro @sentry/cloudflare ``` @@ -60,17 +52,8 @@ yarn add @sentry/astro @sentry/cloudflare pnpm add @sentry/astro @sentry/cloudflare ``` - - - - - - 2. Add the Sentry Astro integration to your `astro.config.mjs`: - - - ```javascript {filename:astro.config.mjs} import { defineConfig } from "astro/config"; import cloudflare from "@astrojs/cloudflare"; @@ -82,17 +65,8 @@ export default defineConfig({ }); ``` - - - - - - 3. - - - ```javascript {filename:functions/_middleware.js} import * as Sentry from "@sentry/cloudflare"; @@ -106,17 +80,8 @@ export const onRequest = [ ]; ``` - - - - - - 4. Make sure to [configure Cloudflare for Sentry](/platforms/javascript/guides/cloudflare/#wrangler-configuration). - - - diff --git a/docs/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.mdx b/docs/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.mdx index f288e761527f27..fad55e7a833250 100644 --- a/docs/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.mdx +++ b/docs/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.mdx @@ -35,15 +35,8 @@ Choose the features you want to configure, and this guide will show you how: ### Install the Sentry SDK - - - - Run the command for your preferred package manager to add the React Router and Cloudflare SDK: - - - ```bash {tabTitle:npm} npm install @sentry/react-router @sentry/cloudflare --save ``` @@ -56,25 +49,14 @@ yarn add @sentry/react-router @sentry/cloudflare pnpm add @sentry/react-router @sentry/cloudflare ``` - - - - ## Configure ### Configure Client-side Sentry - - - - Initialize Sentry in your `entry.client.tsx` file. The `sentryOnError` handler integrates with React Router's [`onError` hook](https://reactrouter.com/how-to/error-reporting) to automatically capture and report client-side errors to Sentry. - - - ```tsx {filename: app/entry.client.tsx} import { HydratedRouter } from "react-router/dom"; import * as Sentry from "@sentry/react-router/cloudflare"; @@ -133,21 +115,10 @@ startTransition(() => { }); ``` - - - - ### Configure Server-side Sentry - - - - First, create an `instrument.server.mjs` file to initialize Sentry on the server: - - - ```js {filename:instrument.server.mjs} import * as Sentry from "@sentry/react-router"; @@ -166,12 +137,6 @@ Sentry.init({ }); ``` - - - - - - Next, update your `server.ts` file to use the `wrapRequestHandler` method from the `@sentry/cloudflare/request` subpath: @@ -186,9 +151,6 @@ On Shopify Oxygen, never import anything directly from `@sentry/cloudflare`. Onl - - - ```ts {filename:server.ts} import { wrapRequestHandler } from "@sentry/cloudflare/request"; // ...other imports @@ -231,23 +193,12 @@ export default { }; ``` - - - - ### Enable Distributed Tracing - - - - Update your `entry.server.tsx` file to inject trace meta tags: - - - ```tsx {filename:app/entry.server.tsx} import "./instrument.server"; import { HandleErrorFunction, ServerRouter } from "react-router"; @@ -289,25 +240,14 @@ export const handleError: HandleErrorFunction = (error, { request }) => { export default Sentry.wrapSentryHandleRequest(handleRequest); ``` - - - - ### Add Readable Stack Traces With Source Maps (Optional) - - - - The stack traces in your Sentry errors probably won't look like your actual code without unminifying them. To fix this, upload your source maps to Sentry. First, update `vite.config.ts` to include the `sentryReactRouter` plugin, making sure to pass both the Vite and Sentry configurations to it. - - - ```ts {filename:vite.config.ts} import { reactRouter } from "@react-router/dev/vite"; import { hydrogen } from "@shopify/hydrogen/vite"; @@ -336,17 +276,8 @@ export default defineConfig((config) => ({ })); ``` - - - - - - Since the `buildEnd` hook will not be executed for Hydrogen, you need to manually upload source maps using the [Sentry CLI](/cli/) instead. - - - ```bash # Inject debug IDs sentry-cli sourcemaps inject /path/to/build/dir @@ -354,10 +285,6 @@ sentry-cli sourcemaps inject /path/to/build/dir sentry-cli sourcemaps upload /path/to/build/dir ``` - - - - ### Control the Data You Send to Sentry (Optional) - - - To verify that Sentry captures errors and creates issues in your Sentry project, throw an error in a loader. Next, open the `/sentry-test` route in your browser, and you should trigger an error. - - - ```tsx {filename: app/routes/sentry-test.tsx} import type { Route } from "./+types/sentry-test"; @@ -397,24 +317,13 @@ export default function SentryTestPage() { } ``` - - - - ### Tracing - - - - To test your tracing configuration, update the previous code snippet by starting a trace to measure the time it takes for the execution of your code. Open the `/sentry-test` route in your browser. You should start a trace and trigger an error. - - - ```tsx {filename: app/routes/sentry-test.tsx} import * as Sentry from "@sentry/react-router/cloudflare"; import type { Route } from "./+types/sentry-test"; @@ -436,10 +345,6 @@ export default function SentryTestPage() { } ``` - - - - diff --git a/docs/platforms/javascript/guides/cloudflare/frameworks/nextjs.mdx b/docs/platforms/javascript/guides/cloudflare/frameworks/nextjs.mdx index f29d1f6f1faf0b..153052f73f9bd6 100644 --- a/docs/platforms/javascript/guides/cloudflare/frameworks/nextjs.mdx +++ b/docs/platforms/javascript/guides/cloudflare/frameworks/nextjs.mdx @@ -53,4 +53,67 @@ compatibility_flags = ["nodejs_compat"] compatibility_date = "2025-08-16" ``` -After adding these settings, build and deploy your Next.js application to Cloudflare Workers. You should start seeing error events, traces, and logs appear in Sentry. +## Wrap the Worker Entry + + + +On Cloudflare Workers, your Next.js app runs inside the Worker entry that OpenNext generates (`.open-next/worker.js`). Wrap this entry with `withSentry` from `@sentry/nextjs/cloudflare` to get the same Next.js spans as on Node.js, plus Cloudflare data such as spans for D1 queries. Each request gets one `http.server` span with the name of the Next.js route, and the Next.js spans become its children. + +`@sentry/nextjs` depends on `@sentry/cloudflare`, so you don't need to install another package. + +First, create a [custom Worker](https://opennext.js.org/cloudflare/howtos/custom-worker) that imports the handler of OpenNext and wraps it with `withSentry`. Pass your Sentry options to `withSentry`: + +```typescript {filename:worker.ts} +import * as Sentry from "@sentry/nextjs/cloudflare"; +// @ts-ignore `.open-next/worker.js` is generated at build time +import handler from "./.open-next/worker.js"; + +// Re-export the Durable Objects your app uses, for example for the DO Queue and DO Tag Cache of OpenNext +// @ts-ignore `.open-next/worker.js` is generated at build time +export { DOQueueHandler, DOShardedTagCache } from "./.open-next/worker.js"; + +export default Sentry.withSentry( + () => ({ + dsn: "___PUBLIC_DSN___", + + // Set tracesSampleRate to 1.0 to capture 100% of spans for tracing. + // Learn more at + // https://docs.sentry.io/platforms/javascript/guides/cloudflare/configuration/options/#tracesSampleRate + tracesSampleRate: 1.0, + }), + handler +); +``` + +Then, point `main` in your Wrangler configuration to this file: + +```json {tabTitle:wrangler.jsonc} +{ + "main": "./worker.ts" +} +``` + +```toml {tabTitle:wrangler.toml} +main = "./worker.ts" +``` + +### Server and Edge Configuration in the Worker + +In the Worker, `withSentry` creates the Sentry client. `Sentry.init()` in `sentry.server.config.ts` and `sentry.edge.config.ts` still runs, but it creates no client and only applies the `release` option. Set all other options in `withSentry`. + +On Workers, these two files are optional. Keep them if you use `next dev`, which runs on Node.js and doesn't use the Worker entry. They also pass on the release that `withSentryConfig` sets at build time. + +Keep `instrumentation.ts`, because Next.js reports server errors, for example from Server Components and route handlers, through its `onRequestError` hook. + +The SDK takes the release from the first of these sources that has a value: + +1. The `release` option of `withSentry` +2. The `SENTRY_RELEASE` environment variable +3. The ID of the `CF_VERSION_METADATA` binding +4. The `release` option of `Sentry.init()` in `sentry.server.config.ts` or `sentry.edge.config.ts`, or else the release that `withSentryConfig` sets at build time + +On Node.js, the build release comes before `SENTRY_RELEASE`. + +## Deploy + +Build and deploy your Next.js application to Cloudflare Workers. You should start seeing error events, traces, and logs appear in Sentry. diff --git a/docs/platforms/javascript/guides/cloudflare/frameworks/remix.mdx b/docs/platforms/javascript/guides/cloudflare/frameworks/remix.mdx index 87b9c85bf2122b..dc987930018ab7 100644 --- a/docs/platforms/javascript/guides/cloudflare/frameworks/remix.mdx +++ b/docs/platforms/javascript/guides/cloudflare/frameworks/remix.mdx @@ -27,17 +27,10 @@ Choose the features you want to configure, and this guide will show you how: ### Install the Sentry SDK - - - - Run the command for your preferred package manager to add the Sentry Remix and Cloudflare SDKs to your application. With npm, add `--legacy-peer-deps`: `@remix-run/cloudflare` requires `@cloudflare/workers-types` version 4, while Wrangler 4 requires version 5. - - - ```bash {tabTitle:npm} npm install @sentry/remix @sentry/cloudflare --save --legacy-peer-deps ``` @@ -50,10 +43,6 @@ yarn add @sentry/remix @sentry/cloudflare pnpm add @sentry/remix @sentry/cloudflare ``` - - - - - - - Run the command for your preferred package manager to add the Sentry SDK to your application: - - - - - - - ## Configure When deploying TanStack Start to Cloudflare Workers, you need to wrap the server entry point with `Sentry.withSentry` from `@sentry/cloudflare`. TanStack Start allows you to create a custom server entry file for this purpose. @@ -58,10 +47,6 @@ When deploying TanStack Start to Cloudflare Workers, you need to wrap the server ### Create a Custom Server Entry - - - - Create a `src/server.ts` file that wraps the TanStack Start handler with Sentry. Use `wrapFetchWithSentry` from `@sentry/tanstackstart-react` to instrument TanStack Start server functions with tracing. @@ -72,9 +57,6 @@ Due to type differences between TanStack Start and Cloudflare Workers, you'll ne - - - ```typescript {filename:src/server.ts} import * as Sentry from "@sentry/cloudflare"; import { wrapFetchWithSentry } from "@sentry/tanstackstart-react"; @@ -95,21 +77,10 @@ export default Sentry.withSentry( ); ``` - - - - ### Update Wrangler Configuration - - - - Update your `wrangler.jsonc` (or `wrangler.toml`) to use your custom server entry: - - - ```json {diff} {filename:wrangler.jsonc} { "name": "my-tanstack-app", @@ -118,21 +89,10 @@ Update your `wrangler.jsonc` (or `wrangler.toml`) to use your custom server entr } ``` - - - - ### Configure Client-Side Sentry - - - - Initialize Sentry in your `src/router.tsx` file for client-side error tracking: - - - ```tsx {diff} {filename:src/router.tsx} +import * as Sentry from "@sentry/tanstackstart-react"; import { createRouter } from '@tanstack/react-router' @@ -177,16 +137,8 @@ export const getRouter = () => { } ``` - - - - ### Capture Server-Side Errors - - - - To capture server-side errors from HTTP requests and server function calls, add Sentry's global middlewares to `createStart()` in your `src/start.ts` file. The Sentry middleware should be the first middleware in the arrays to ensure all errors are captured. @@ -196,9 +148,6 @@ The Sentry middleware should be the first middleware in the arrays to ensure all `captureException` to manually capture those errors. - - - ```tsx {filename:src/start.ts} import { sentryGlobalFunctionMiddleware, @@ -214,10 +163,6 @@ export const startInstance = createStart(() => { }); ``` - - - - ### Add Readable Stack Traces With Source Maps (Optional) { ## Verify Your Setup - - - - To verify Sentry is capturing errors, add a test button to one of your pages: - - - ```tsx ``` - - - - - - Then, in your renderer, add the following: Finally, start your app and trigger two errors that Sentry will capture: one from the main process and one from the renderer. - - ```javascript document.getElementById("testError").addEventListener("click", () => { @@ -316,24 +216,13 @@ document.getElementById("testError").addEventListener("click", () => { }); ``` - - - - ### Tracing - - - - To test tracing in your renderer, start a trace to measure the time it takes to execute your code. Then, start your app and trigger two errors that Sentry will capture: one from the main process and one from the renderer. It will also start a trace with the defined name. - - - ```javascript document.getElementById("testError").addEventListener("click", () => { Sentry.startSpan({ op: "test", name: "Renderer test span" }, () => { @@ -342,10 +231,6 @@ document.getElementById("testError").addEventListener("click", () => { }); ``` - - - - diff --git a/docs/platforms/javascript/guides/elysia/index.mdx b/docs/platforms/javascript/guides/elysia/index.mdx index d9a6b4ca920c9b..7e1cf220de0a05 100644 --- a/docs/platforms/javascript/guides/elysia/index.mdx +++ b/docs/platforms/javascript/guides/elysia/index.mdx @@ -37,10 +37,6 @@ Choose the features you want to configure, and this guide will show you how: ### Install the Sentry SDK - - - - Run the command for your runtime and preferred package manager to add the Sentry SDK to your application: @@ -48,9 +44,6 @@ Run the command for your runtime and preferred package manager to add the Sentry handles all instrumentation natively. - - - ```bash {tabTitle:Bun} {mdExpandTabs} bun add @sentry/elysia ``` @@ -63,21 +56,10 @@ yarn add @sentry/elysia @elysiajs/node pnpm add @sentry/elysia @elysiajs/node ``` - - - - ## Configure - - - - Call `Sentry.init()` before creating your Elysia app, then wrap the app with `Sentry.withElysia()` before defining routes. - - - ```javascript {tabTitle:Bun} {mdExpandTabs} {filename: index.ts} import * as Sentry from "@sentry/elysia"; import { Elysia } from "elysia"; @@ -125,22 +107,11 @@ const app = Sentry.withElysia(new Elysia({ adapter: node() })) .listen(3000); ``` - - - - ### Customize Automatic Error Capturing (Optional) - - - - The SDK captures 5xx errors automatically via a global `onError` hook. Client errors (3xx/4xx) are not captured by default. You can customize which errors are captured using the `shouldHandleError` option. - - - ```javascript const app = Sentry.withElysia(new Elysia(), { shouldHandleError: (context) => { @@ -150,10 +121,6 @@ const app = Sentry.withElysia(new Elysia(), { }); ``` - - - - ### Add Readable Stack Traces With Source Maps (Optional) @@ -168,38 +135,20 @@ Let's test your setup and confirm that Sentry is working correctly and sending d ### Issues - - - - First, let's verify that Sentry captures errors and creates issues in your Sentry project. Add the following route to your app, which triggers an error that Sentry will capture: - - - ```javascript app.get("/debug-sentry", () => { throw new Error("My first Sentry error!"); }); ``` - - - - ### Tracing - - - - To test your tracing configuration, update the previous code snippet by starting a trace to measure the time it takes for the execution of your code: - - - ```javascript app.get("/debug-sentry", async () => { await Sentry.startSpan( @@ -215,10 +164,6 @@ app.get("/debug-sentry", async () => { }); ``` - - - - diff --git a/docs/platforms/javascript/guides/ember/index.mdx b/docs/platforms/javascript/guides/ember/index.mdx index 93e9edc4cd3c9f..ba92dfd4ed7fa5 100644 --- a/docs/platforms/javascript/guides/ember/index.mdx +++ b/docs/platforms/javascript/guides/ember/index.mdx @@ -15,21 +15,10 @@ categories: ### Install the Sentry SDK - - - - Run the command for your preferred package manager to add the Sentry SDK to your application: - - - - - - - ## Configure **Error Monitoring** starts working as soon as you call `Sentry.init()`. **Logs** and **Application Metrics** need no extra configuration, and you'll learn how to send them in steps [#3](#send-logs) and [#4](#send-application-metrics-). @@ -39,10 +28,6 @@ This guide also enables **Tracing**, **Session Replay**, and **User Feedback**. ### Initialize the SDK - - - - Call `Sentry.init()` in `app/app.ts` before defining your `Application` class. The snippet also turns on: @@ -53,9 +38,6 @@ The snippet also turns on: Don't need a feature? Remove its integration and options from the snippet. - - - ```typescript {filename:app/app.ts} import Application from "@ember/application"; import Resolver from "ember-resolver"; @@ -97,23 +79,12 @@ export default class App extends Application { loadInitializers(App, config.modulePrefix); ``` - - - - ### Enable Performance Instrumentation - - - - To capture page loads, navigation, classic component renders, and runloop timings, create an instance initializer that calls `instrumentAppInstancePerformance()`. The `tracesSampleRate` option in `Sentry.init()` controls how much tracing data Sentry captures. The SDK skips this instrumentation during FastBoot server rendering. To customize it, see Ember Options. - - - ```typescript {filename:app/instance-initializers/sentry-performance.ts} import type ApplicationInstance from "@ember/application/instance"; import { instrumentAppInstancePerformance } from "@sentry/ember"; @@ -125,10 +96,6 @@ export function initialize(appInstance: ApplicationInstance): void { export default { initialize }; ``` - - - - ### Add Readable Stack Traces With Source Maps @@ -139,10 +106,6 @@ export default { initialize }; ## Send Logs - - - - Use `Sentry.logger` to send logs at different levels, such as `info`, `warn`, or `error`. You can pass any attributes you want and search or filter by them later. @@ -150,9 +113,6 @@ If you're already logging with `console` or [Consola](https://github.com/unjs/co See Set Up Logs for all available logging methods and the syntax for formatting messages. - - - ```javascript Sentry.logger.info("User example action completed"); @@ -167,24 +127,13 @@ Sentry.logger.error("Validation failed", { }); ``` - - - - ## Send Application Metrics - - - - Use `Sentry.metrics` to send counters, gauges, and distributions from your app to Sentry. You can pass any attributes you want and search or filter by them later. See Set Up Metrics for all available metric types and configuration options. - - - ```javascript Sentry.metrics.count("checkout.failed", 1); @@ -196,21 +145,11 @@ Sentry.metrics.distribution("api_latency", 187, { }); ``` - - - - ## Verify Your Setup Let's test your setup and confirm that Sentry is working correctly and sending data to your Sentry project. - - - - Add the following test button to one of your templates, which will trigger an error when you click it: - - ```handlebars {filename: application.hbs} {{! rest of your page }} @@ -219,16 +158,8 @@ Add the following test button to one of your templates, which will trigger an er ``` - - - - - Next, add the corresponding action to your controller or component. - - - ```javascript {filename: application.js} import Controller from "@ember/controller"; import { action } from "@ember/object"; @@ -241,10 +172,6 @@ export default class ApplicationController extends Controller { } ``` - - - - ### View Captured Data in Sentry diff --git a/docs/platforms/javascript/guides/firebase/index.mdx b/docs/platforms/javascript/guides/firebase/index.mdx index 0549b511e808e2..62a9a512564497 100644 --- a/docs/platforms/javascript/guides/firebase/index.mdx +++ b/docs/platforms/javascript/guides/firebase/index.mdx @@ -38,15 +38,8 @@ Choose the features you want to configure, and this guide will show you how: ### Install the Sentry SDK - - - - Run the command for your preferred package manager to add the Sentry SDK to your Firebase Functions project: - - - ```bash {tabTitle:npm} @@ -79,21 +72,10 @@ pnpm add @sentry/node @sentry/profiling-node - - - - ## Configure - - - - Create an initialization file (for example, `instrument.js`) that imports and initializes Sentry. - - - ```javascript {filename:instrument.js} const Sentry = require("@sentry/node"); // ___PRODUCT_OPTION_START___ profiling @@ -131,12 +113,6 @@ Sentry.init({ }); ``` - - - - - - Import the initialization file at the very top of your functions entry point (for example, `index.js`), before any other imports: @@ -144,8 +120,6 @@ Import the initialization file at the very top of your functions entry point (fo calls, including Firebase imports. This ensures Sentry can properly instrument all modules. - - ```javascript {filename:index.js} require("./instrument"); // Require Sentry initialization first @@ -168,10 +142,6 @@ exports.onUserCreated = onDocumentCreated("users/{userId}", async (event) => { }); ``` - - - - ### Add Readable Stack Traces With Source Maps (Optional) @@ -186,15 +156,8 @@ Let's test your setup and confirm that Sentry is working correctly and sending d ### Issues - - - - Add a test function that throws an error to verify Sentry is capturing errors: - - - ```javascript {filename:index.js} require("./instrument"); // Import Sentry initialization first const { onRequest } = require("firebase-functions/https"); @@ -204,39 +167,19 @@ exports.testSentry = onRequest(async (request, response) => { }); ``` - - - - - - Deploy your functions and trigger the test endpoint: - - - ```bash firebase deploy --only functions curl https://-.cloudfunctions.net/testSentry ``` - - - - ### Tracing - - - - Firebase Functions are automatically instrumented for tracing. You can also create custom spans: - - - ```javascript {filename:index.js} require("./instrument"); const Sentry = require("@sentry/node"); @@ -252,10 +195,6 @@ exports.tracedFunction = onRequest(async (request, response) => { }); ``` - - - - diff --git a/docs/platforms/javascript/guides/gatsby/index.mdx b/docs/platforms/javascript/guides/gatsby/index.mdx index dc90aa371da114..1e077dfe392fd8 100644 --- a/docs/platforms/javascript/guides/gatsby/index.mdx +++ b/docs/platforms/javascript/guides/gatsby/index.mdx @@ -15,10 +15,6 @@ categories: ### Install the Sentry SDK - - - - Run the command for your preferred package manager to add the Sentry SDK to your application. @@ -27,9 +23,6 @@ Run the command for your preferred package manager to add the Sentry SDK to your - - - ```bash {tabTitle:npm} npm install @sentry/gatsby --save ``` @@ -42,21 +35,10 @@ yarn add @sentry/gatsby pnpm add @sentry/gatsby ``` - - - - ### Register the Sentry SDK - - - - Register `@sentry/gatsby` in your Gatsby configuration file (typically `gatsby-config.(js|ts)`). - - - ```javascript {tabTitle: CommonJS}{filename:gatsby-config.(js|ts)} module.exports = { plugins: [ @@ -82,10 +64,6 @@ const config: GatsbyConfig = { export default config; ``` - - - - ## Configure Choose the features you want to configure, and this guide will show you how: @@ -103,15 +81,8 @@ Choose the features you want to configure, and this guide will show you how: ### Initialize the Sentry SDK - - - - Initialize Sentry as early as possible in your application. For this, create a new file `sentry.config.(js|ts)` in your project root and add the following: - - - ```javascript {filename:sentry.config.(js|ts)} import * as Sentry from "@sentry/gatsby"; @@ -153,10 +124,6 @@ Sentry.init({ }); ``` - - - - ### Add Readable Stack Traces With Source Maps (Optional) @@ -175,10 +142,6 @@ Let's test your setup and confirm that Sentry is working correctly and sending d ### Issues - - - - To verify that Sentry captures errors and creates issues in your Sentry project, add the following test button to one of your pages. @@ -188,9 +151,6 @@ To verify that Sentry captures errors and creates issues in your Sentry project, - - - ```javascript {filename:index.(jsx|tsx)}