33import static datadog .trace .api .ConfigDefaults .DEFAULT_ASYNC_PROPAGATING ;
44import static datadog .trace .bootstrap .instrumentation .api .AgentTracer .noopScope ;
55import static datadog .trace .bootstrap .instrumentation .api .AgentTracer .noopSpan ;
6+ import static datadog .trace .core .scopemanager .ContinuableScope .CONTEXT ;
67import static datadog .trace .core .scopemanager .ContinuableScope .INSTRUMENTATION ;
78import static datadog .trace .core .scopemanager .ContinuableScope .ITERATION ;
89import static datadog .trace .core .scopemanager .ContinuableScope .MANUAL ;
910import static java .util .concurrent .TimeUnit .MINUTES ;
1011import static java .util .concurrent .TimeUnit .NANOSECONDS ;
1112import static java .util .concurrent .TimeUnit .SECONDS ;
1213
14+ import datadog .context .Context ;
15+ import datadog .context .ContextManager ;
16+ import datadog .context .ContextScope ;
1317import datadog .trace .api .Config ;
1418import datadog .trace .api .Stateful ;
1519import datadog .trace .api .scopemanager .ExtendedScopeListener ;
4044 * from being reported even if all related spans are finished. It also delegates to other
4145 * ScopeInterceptors to provide additional functionality.
4246 */
43- public final class ContinuableScopeManager implements ScopeStateAware {
47+ public final class ContinuableScopeManager implements ScopeStateAware , ContextManager {
4448
4549 static final Logger log = LoggerFactory .getLogger (ContinuableScopeManager .class );
4650 static final RatelimitedLogger ratelimitedLog = new RatelimitedLogger (log , 1 , MINUTES );
@@ -83,6 +87,8 @@ public ContinuableScopeManager(
8387 this .healthMetrics = healthMetrics ;
8488 this .tlsScopeStack = new ScopeStackThreadLocal (profilingContextIntegration );
8589 this .profilingContextIntegration = profilingContextIntegration ;
90+
91+ ContextManager .register (this );
8692 }
8793
8894 public AgentScope activateSpan (final AgentSpan span ) {
@@ -96,10 +102,12 @@ public AgentScope activateManualSpan(final AgentSpan span) {
96102 public AgentScope .Continuation captureActiveSpan () {
97103 ContinuableScope activeScope = scopeStack ().active ();
98104 if (null != activeScope && activeScope .isAsyncPropagating ()) {
99- return captureSpan (activeScope .span (), activeScope .source ());
100- } else {
101- return AgentTracer .noopContinuation ();
105+ AgentSpan span = activeScope .span ();
106+ if (span != null ) {
107+ return captureSpan (span , activeScope .source ());
108+ }
102109 }
110+ return AgentTracer .noopContinuation ();
103111 }
104112
105113 public AgentScope .Continuation captureSpan (final AgentSpan span ) {
@@ -111,14 +119,14 @@ private AgentScope.Continuation captureSpan(final AgentSpan span, byte source) {
111119 }
112120
113121 private AgentScope activate (
114- final AgentSpan span ,
122+ final Context context ,
115123 final byte source ,
116124 final boolean overrideAsyncPropagation ,
117125 final boolean isAsyncPropagating ) {
118126 ScopeStack scopeStack = scopeStack ();
119127
120128 final ContinuableScope top = scopeStack .top ;
121- if (top != null && top .span .equals (span )) {
129+ if (top != null && top .context .equals (context )) {
122130 top .incrementReferences ();
123131 return top ;
124132 }
@@ -131,7 +139,7 @@ private AgentScope activate(
131139 return noopScope ();
132140 }
133141
134- assert span != null ;
142+ assert context != null ;
135143
136144 // Inherit the async propagation from the active scope unless the value is overridden
137145 boolean asyncPropagation =
@@ -140,7 +148,7 @@ private AgentScope activate(
140148 : top != null ? top .isAsyncPropagating () : DEFAULT_ASYNC_PROPAGATING ;
141149
142150 final ContinuableScope scope =
143- new ContinuableScope (this , span , source , asyncPropagation , createScopeState (span ));
151+ new ContinuableScope (this , context , source , asyncPropagation , createScopeState (context ));
144152 scopeStack .push (scope );
145153 healthMetrics .onActivateScope ();
146154
@@ -153,26 +161,26 @@ private AgentScope activate(
153161 * @param continuation {@code null} if a continuation is re-used
154162 */
155163 ContinuableScope continueSpan (
156- final ScopeContinuation continuation , final AgentSpan span , final byte source ) {
164+ final ScopeContinuation continuation , final Context context , final byte source ) {
157165 ScopeStack scopeStack = scopeStack ();
158166
159167 // optimization: if the top scope is already keeping the same span alive
160168 // then re-use that scope (avoids allocation) and cancel the continuation
161169 final ContinuableScope top = scopeStack .top ;
162- if (top != null && top .span .equals (span )) {
170+ if (top != null && top .context .equals (context )) {
163171 top .incrementReferences ();
164172 if (continuation != null ) {
165173 continuation .cancelFromContinuedScopeClose ();
166174 }
167175 return top ;
168176 }
169177
170- Stateful scopeState = createScopeState (span );
178+ Stateful scopeState = createScopeState (context );
171179 final ContinuableScope scope ;
172180 if (continuation != null ) {
173- scope = new ContinuingScope (this , span , source , true , continuation , scopeState );
181+ scope = new ContinuingScope (this , context , source , true , continuation , scopeState );
174182 } else {
175- scope = new ContinuableScope (this , span , source , true , scopeState );
183+ scope = new ContinuableScope (this , context , source , true , scopeState );
176184 }
177185 scopeStack .push (scope );
178186
@@ -202,8 +210,9 @@ public void closePrevious(final boolean finishSpan) {
202210 }
203211 top .close ();
204212 scopeStack .cleanup ();
205- if (finishSpan ) {
206- top .span .finishWithEndToEnd ();
213+ AgentSpan span = top .span ();
214+ if (finishSpan && span != null ) {
215+ span .finishWithEndToEnd ();
207216 }
208217 }
209218 }
@@ -261,7 +270,7 @@ public void rollbackActiveToCheckpoint() {
261270
262271 public AgentSpan activeSpan () {
263272 final ContinuableScope active = scopeStack ().active ();
264- return active == null ? null : active .span ;
273+ return active == null ? null : active .span () ;
265274 }
266275
267276 /** Attach a listener to scope activation events */
@@ -289,11 +298,12 @@ private void addExtendedScopeListener(final ExtendedScopeListener listener) {
289298 }
290299 }
291300
292- private Stateful createScopeState (AgentSpan span ) {
301+ private Stateful createScopeState (Context context ) {
293302 // currently this just manages things the profiler has to do per scope, but could be expanded
294303 // to encapsulate other scope lifecycle activities
295304 // FIXME DDSpanContext is always a ProfilerContext anyway...
296- if (span .context () instanceof ProfilerContext ) {
305+ AgentSpan span = AgentSpan .fromContext (context );
306+ if (span != null && span .context () instanceof ProfilerContext ) {
297307 return profilingContextIntegration .newScopeState ((ProfilerContext ) span .context ());
298308 }
299309 return Stateful .DEFAULT ;
@@ -308,6 +318,22 @@ public ScopeState newScopeState() {
308318 return new ContinuableScopeState ();
309319 }
310320
321+ @ Override
322+ public Context current () {
323+ final ContinuableScope active = scopeStack ().active ();
324+ return active == null ? Context .root () : active .context ;
325+ }
326+
327+ @ Override
328+ public ContextScope attach (Context context ) {
329+ return activate (context , CONTEXT , false , true );
330+ }
331+
332+ @ Override
333+ public Context swap (Context context ) {
334+ throw new UnsupportedOperationException ("Not yet implemented" );
335+ }
336+
311337 private class ContinuableScopeState implements ScopeState {
312338
313339 private ScopeStack localScopeStack = tlsScopeStack .initialValue ();
@@ -383,11 +409,14 @@ public void run(Map<ScopeStack, ContinuableScope> rootIterationScopes) {
383409
384410 if (!rootScope .alive ()) { // no need to track this anymore
385411 itr .remove ();
386- } else if (NANOSECONDS .toMillis (rootScope .span .getStartTime ()) < cutOff ) {
387- // mark scope as overdue to allow cleanup and avoid further spans being attached
388- scopeStack .overdueRootScope = rootScope ;
389- rootScope .span .finishWithEndToEnd ();
390- itr .remove ();
412+ } else {
413+ AgentSpan span = rootScope .span ();
414+ if (span != null && NANOSECONDS .toMillis (span .getStartTime ()) < cutOff ) {
415+ // mark scope as overdue to allow cleanup and avoid further spans being attached
416+ scopeStack .overdueRootScope = rootScope ;
417+ span .finishWithEndToEnd ();
418+ itr .remove ();
419+ }
391420 }
392421 }
393422 }
0 commit comments