You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
## Advantages over using Sentry without OpenTelemetry
15
+
16
+
- Support for more libraries and frameworks
17
+
- See https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation for a list of supported libraries and frameworks
18
+
- More automated Performance instrumentation (spans) created
19
+
- Using `sentry-opentelemetry-agent` offers most support
20
+
- Using `sentry-opentelemetry-agentless-spring` for Spring Boot also has a lot of supported libraries, altough fewer than the agent does
21
+
- Note that `sentry-opentelemetry-agentless` will not have any OpenTelemetry auto instrumentation
22
+
- Sentry also relies on OpenTelemetry `Context` propagation to propagate Sentry `Scopes`, ensuring e.g. that execution flow for a request shares data and does not leak data into other requests.
23
+
- OpenTelemetry also offers better support for distributed tracing since more libraries are supported for attaching tracing information to outgoing requests and picking up incoming tracing information.
24
+
25
+
## Key Components
26
+
27
+
### Agent vs Agentless
28
+
29
+
**Agent-based integration**:
30
+
- Automatic instrumentation via Java agent
31
+
- Can be added to any JAR when starting, no extra dependencies or code changes required. Just add the agent to the `java` command.
32
+
- Uses OpenTelemetry Java agent with Sentry extensions
33
+
- Uses bytecode manipulation
34
+
35
+
**Agentless-Spring integration**:
36
+
- Automatic instrumentation setup via Spring Boot
37
+
- Dependency needs to be added to the project.
38
+
39
+
**Agentless integration**:
40
+
- Manual instrumentation setup
41
+
- Dependency needs to be added to the project.
42
+
43
+
**Manual Integration**:
44
+
While it's possible to manually wire up all the required classes to make Sentry and OpenTelemetry work together, we do not recommend this.
45
+
It is instead preferrable to go through `SentryAutoConfigurationCustomizerProvider` so the Sentry SDK has a place to manage required classes and update it when changes are needed.
46
+
This way customers receive the updated config automatically as oppposed to having to update manually, wire in new classes, remove old ones etc.
47
+
48
+
### Integration Architecture
49
+
50
+
Sentry will try to locate certain classes that come with the Sentry OpenTelemetry integration to:
51
+
- Determine whether any Sentry OpenTelemetry integration is present
52
+
- Determine which mode to use and in turn which Sentry auto instrumentation to suppress
53
+
54
+
Reflection is used to search for `io.sentry.opentelemetry.OtelContextScopesStorage` and use it instead of `DefaultScopesStorage` when a Sentry OpenTelemetry integration is present at runtime. `IScopesStorage` is used to store Sentry `Scopes` instances. `DefaultScopesStorage` will use a thread local variable to store the current threads `Scopes` whereas `OtelContextScopesStorage` makes use of OpenTelemetry SDKs `Context`. Sentry OpenTelemetry integrations configure OpenTelemetry to use `SentryOtelThreadLocalStorage` to customize restoring of the previous `Context`.
55
+
56
+
OpenTelemetry SDK makes use of `io.opentelemetry.context.Scope` in `try` with statements that call `close` when a code block is finished. Without customization, it would refuse to restore the previous `Context` onto the `ThreadLocal` if the current state of the `ThreadLocal` isn't the same as the one this scope was created for. Sentry changes this behaviour in `SentryScopeImpl` to restore the previous `Context` onto the `ThreadLocal` even if an inner `io.opentelemetry.context.Scope` wasn't properly cleaned up. Our thinking here is to prefer returning to a clean state as opposed to propagating the problem. The unclean state could happen, if `io.opentelemetry.context.Scope` isn't closed, e.g. when forgetting to put it in a `try` with statement and not calling `close` (e.g. not putting it in a `finally` block in that case).
57
+
58
+
`SentryContextStorageProvider` looks for any other `ContextStorageProvider` and forwards to that to not override any customized `ContextStorage`. If no other provider is found, `SentryOtelThreadLocalStorage` is used.
59
+
60
+
`SpanFactoryFactory` is used to configure Sentry to use `io.sentry.opentelemetry.OtelSpanFactory` if the class is present at runtime. Reflection is used to search for it. If the class is not available, we fall back to `DefaultSpanFactory`.
61
+
62
+
`DefaultSpanFactory` creates a `SentryTracer` instance when creating a transaction and spans are then created directly on the transaction via `startChild`.
63
+
`OtelSpanFactory` instead creates an OpenTelemetry span and wraps it using `OtelTransactionSpanForwarder` to simulate a transaction. The `startChild` invocations on `OtelTransactionSpanForwarder` go through `OtelSpanFactory` again to create the child span.
64
+
65
+
## Configuration
66
+
67
+
We use `SentryAutoConfigurationCustomizerProvider` to configure OpenTelemetry for use with Sentry and register required classes, hooks etc.
68
+
69
+
## Span Processing
70
+
71
+
Both Sentry and OpenTelemetry API can be used to create spans. When using Sentry API, `OtelSpanFactory` is used to indirectly create a OpenTelemetry span.
72
+
Regardless of API used, when an OpenTelemetry span is created, it goes through `SentrySampler` for sampling and `OtelSentrySpanProcessor` for `Scopes` forking and ensuring the trace is continued.
73
+
When Sentry API is used, sampling is performed in `Scopes.createTransaction` before forwarding the call to `OtelSpanFactory`. The sampling decision and other sampling details are forwarded to `SentrySampler` and `OtelSentrySpanProcessor`.
74
+
75
+
When a span is finished, regardless of whether Sentry or OpenTelemetry API is used, it goes through `OtelSentrySpanProcessor` to set the end date and then through `BatchSpanProcessor` which will batch spans and then forward them to `SentrySpanExporter`.
76
+
77
+
`SentrySpanExporter` collects spans, then structures them to create a transaction for the local root span and attaches child spans to form a span tree.
78
+
Some OpenTelemetry attributes are transformed into their corresponding Sentry data structure or format.
79
+
80
+
After creating the transaction with child spans `SentrySpanExporter` uses Sentry API to send the transaction to Sentry. This API call however forces the use of `DefaultSpanFactory` in order to create the required Sentry classes for sending and also to not create an infinite loop where any span created will cause a new span to be created recursively.
81
+
82
+
## Troubleshooting
83
+
84
+
To debug forking of `Scopes`, we added a reference to `parent` `Scopes` and a `creator` String to store the reason why `Scopes` were created or forked.
0 commit comments