-
-
Notifications
You must be signed in to change notification settings - Fork 461
Closed
Description
- Notion POTEL Doc
- Talked to Francesco to learn from Node/JS changes
### Statement on OTel support - tech feasibility and quality
- [ ] Java (and frameworks)
- [ ] Kotlin
- [ ] Android
- Currently working on a backend POC
- trying to translate JS to Java then go from there and check for blockers, required API changes etc.
- increasing internal list of spans
- requests to sentry are not filtered properly
- spans are reported mulitple times with increasing duration
- Check differences in context handling
- Also need to do a POC for Android + OTEL to check for blockers
- Check how good auto instrumentation for Spring (Boot) is without the Agent
Context Handling
Attributes vs Context
- Attributes can only hold few types (
String,Boolean,Long,Double) and arrays thereof (seeAttributeType) - Context can also hold complex types
- Need to test whether
Context.current()works inSpanProcessor- Initial test looks promising
- but there might be more complex scenarios where this does not work
- Attributes can be retrieved from
ReadableSpaninSpanProcessor.onEnd() - Context can not be retrieved from
ReadableSpan - Context has an internal split, when
AgentContextWrapperis used (presumably this is always the case when using the OTEL Java Agent)agentContextvsapplicationContext
ContextStorageProvider
- We could implement a custom
ContextStorageProviderto intercept whenever context is replaced and fork scope - We'll also have to figure out when to fork isolation scope
Hubs and Scopes merge
- https://develop.sentry.dev/sdk/hub_and_scope_refactoring/
- Hub will be removed long term (future major release)
- Hub can simply forward to scope under the hood so we may be able to change the code without requiring a major
Execution context
- Should we explicitly have
ExecutionContextin code to wrap isolation scope, current scope and maybe also current span? - Would be the replacement thread local variable for
currentHub
Scopes
- There will be multiple scopes
- Global scope
- Truely global scope (process wide), not per client
- Can be written to even before
Sentry.init - Can be used e.g. to add tags that will be added to all events etc.
- before this basically required users to add tags immediately after
Sentry.initwas called - this can now be customized even from asynchronously running code, e.g. after some lib initializes or after some API call was made
- before this basically required users to add tags immediately after
- Holds a reference to the default global client
- to add tags, set user etc. users need to explicitly perform
Sentry.getGlobalScope().setTag()etc.
- Isolation scope
- similar to a global scope, but tied to a specific section of your app/code that should be isolated
- e.g. for the duration of handling a request server side
- Users don't have to worry about writing to a scope that doesn't apply to the whole request by accident, they can now use isolation scope e.g. to add tags or set a user that is applied to the whole request
- Global methods to set data, like
Sentry.setTag()orSentry.setUser(), will set on the isolation scope.
- similar to a global scope, but tied to a specific section of your app/code that should be isolated
- Current scope
- Global methods that capture like
Sentry.captureException(e)will capture on the current scope - While capturing global scope, isolation scope and current scope are merged and applied to events
- Global methods that capture like
- Global scope
Scope forking
See https://miro.com/app/board/uXjVNtPiOfI=/
- When forking current scope (
with new_scope)- forks current scope and sets the fork as active current scope
- does not fork isolation scope (isolation scope remains untouched)
- this is the only of these methods that's part of public API, others can be usable by users but not part of public API directly
- When setting current scope (
with use_scope(scope))- uses passed in scope as active current scope
- does not fork current scope
- isolation scope remains untouched
- When forking isolation scope (
with isolation_scope)- forks isolation scope and sets the fork as active isolation scope
- forks current scope and sets the fork as active current scope
- When setting isolation scope (
with use_isolation_scope(isolation_scope))- uses passed in isolation scope as active isolation scope
- do we even need this?
- When setting isolation scope and current scope
- uses passed in isolation scope as active isolation scope
- uses passed in current scope as active current scope
- does not fork either scope
- maybe this should be called
with execution_context(execution_context)
Applying scopes to events
public captureEvent(event: Event, additionalScope?: Scope) {
// Global scope is always applied first
const scopeData = getGlobalScope().getScopeData();
// Apply isolations cope next
const isolationScope = getIsolationScope();
merge(scopeData, isolationScope.getScopeData());
// Now the scope data itself is added
merge(scopeData, this.getScopeData());
// If defined, add the captureContext/scope
// This is e.g. what you pass to Sentry.captureException(error, { tags: [] })
if (additionalScope) {
merge(scopeData, additionalScope.getScopeData());
}
// Finally, this is merged with event data, where event data takes precedence!
mergeIntoEvent(event, scopeData);
}
}
Transferring execution context
- When moving execution from one thread to another, we should set isolation scope and current scope to the same ones on the new thread
- For reactive programming libraries we'll have to backup and restore isolation scope, current scope and maybe also the current span (if it's not set on the scope but directly on execution context)
- We should probably not fork isolation scope likely to not diminish its usefulness
- see https://miro.com/app/board/uXjVNtPiOfI=/
Tracing without Performance (TwP) / PropagationContext
- Should this be put on isolation scope?
- Should we have a more abstract API for isolation that
- forks isolation scope
- forks current scope
- creates a new PropagationContext
Copy on write
- Scopes should only be actually copied when there's a change.
- For current scope there should be a very limited number of actual changes but lots of forks
- Is the most likely change happening setting a new active span?
Locking
- we usually lock write access to scope via withPropagationContext, withSession, setTransaction/clearTransaction, startSession/endSession, how will this behave in the future?
Lifecycle management
- Things like
pushScopeandpushIsolationScopecould return anAutoClosablewhere onclosewe restore the previous scope. This would allow users to simply writetry(x = pushScope()) { ... }instead of manually having to popScope. It'd also allow for restoring previous state without risking an imbalance betweenpushScopeandpopScopecalls. OTEL does this, e.g. inContext.makeCurrent().
Migration docs
- May need to make it extra clear in changelog, migration guide etc. that top level API (e.g.
Sentry.setTag()) now goes to isolation scope whereas e.g.Sentry.configureScope(s -> s.setTag())goes to the current scope. This may lead to unexpected scope leaks for our users. - scope
- pushScope+popScope -> ?
- withScope -> ?
- configureScope -> ?
- direct hub usage
- hub.captureX -> scope.captureX ?
Document common use cases
- setting tags, breadcrumbs, user, ... for the current request ->
Sentry.addTag() - setting tags, breadcrumbs, user, ... globally ->
Sentry.getGlobalScope().setXetc.
Metadata
Metadata
Assignees
Labels
No labels
Projects
Status
Done