@@ -189,37 +189,46 @@ public StoredContext newEmptySystemContext() {
189189 * moving tracing-related fields to different names so that a new child span can be started. This child span will pick up
190190 * the moved fields and use them to establish the parent-child relationship.
191191 *
192+ * Response headers will be propagated. If no parent span is in progress (meaning there's no trace context), this will behave exactly
193+ * the same way as {@link #newStoredContextPreservingResponseHeaders}.
194+ *
192195 * @return a stored context, which can be restored when this context is no longer needed.
193196 */
194197 public StoredContext newTraceContext () {
195198 final ThreadContextStruct originalContext = threadLocal .get ();
196- final Map <String , String > newRequestHeaders = new HashMap <>(originalContext .requestHeaders );
197- final Map <String , Object > newTransientHeaders = new HashMap <>(originalContext .transientHeaders );
198199
199- final String previousTraceParent = newRequestHeaders .remove (Task .TRACE_PARENT_HTTP_HEADER );
200- if (previousTraceParent != null ) {
201- newTransientHeaders .put (Task .PARENT_TRACE_PARENT_HEADER , previousTraceParent );
202- }
200+ // this is the context when this method returns
201+ final ThreadContextStruct newContext ;
202+ if (originalContext .hasTraceContext () == false ) {
203+ newContext = originalContext ;
204+ } else {
205+ final Map <String , String > newRequestHeaders = new HashMap <>(originalContext .requestHeaders );
206+ final Map <String , Object > newTransientHeaders = new HashMap <>(originalContext .transientHeaders );
203207
204- final String previousTraceState = newRequestHeaders .remove (Task .TRACE_STATE );
205- if (previousTraceState != null ) {
206- newTransientHeaders .put (Task .PARENT_TRACE_STATE , previousTraceState );
207- }
208+ final String previousTraceParent = newRequestHeaders .remove (Task .TRACE_PARENT_HTTP_HEADER );
209+ if (previousTraceParent != null ) {
210+ newTransientHeaders .put (Task .PARENT_TRACE_PARENT_HEADER , previousTraceParent );
211+ }
208212
209- final Object previousTraceContext = newTransientHeaders .remove (Task .APM_TRACE_CONTEXT );
210- if (previousTraceContext != null ) {
211- newTransientHeaders .put (Task .PARENT_APM_TRACE_CONTEXT , previousTraceContext );
212- }
213+ final String previousTraceState = newRequestHeaders .remove (Task .TRACE_STATE );
214+ if (previousTraceState != null ) {
215+ newTransientHeaders .put (Task .PARENT_TRACE_STATE , previousTraceState );
216+ }
213217
214- // this is the context when this method returns
215- final ThreadContextStruct newContext = new ThreadContextStruct (
216- newRequestHeaders ,
217- originalContext .responseHeaders ,
218- newTransientHeaders ,
219- originalContext .isSystemContext ,
220- originalContext .warningHeadersSize
221- );
222- threadLocal .set (newContext );
218+ final Object previousTraceContext = newTransientHeaders .remove (Task .APM_TRACE_CONTEXT );
219+ if (previousTraceContext != null ) {
220+ newTransientHeaders .put (Task .PARENT_APM_TRACE_CONTEXT , previousTraceContext );
221+ }
222+
223+ newContext = new ThreadContextStruct (
224+ newRequestHeaders ,
225+ originalContext .responseHeaders ,
226+ newTransientHeaders ,
227+ originalContext .isSystemContext ,
228+ originalContext .warningHeadersSize
229+ );
230+ threadLocal .set (newContext );
231+ }
223232 // Tracing shouldn't interrupt the propagation of response headers, so in the same as
224233 // #newStoredContextPreservingResponseHeaders(), pass on any potential changes to the response headers.
225234 return () -> {
@@ -233,10 +242,11 @@ public StoredContext newTraceContext() {
233242 }
234243
235244 public boolean hasTraceContext () {
236- final ThreadContextStruct context = threadLocal .get ();
237- return context .requestHeaders .containsKey (Task .TRACE_PARENT_HTTP_HEADER )
238- || context .requestHeaders .containsKey (Task .TRACE_STATE )
239- || context .transientHeaders .containsKey (Task .APM_TRACE_CONTEXT );
245+ return threadLocal .get ().hasTraceContext ();
246+ }
247+
248+ public boolean hasParentTraceContext () {
249+ return threadLocal .get ().hasParentTraceContext ();
240250 }
241251
242252 /**
@@ -853,6 +863,18 @@ private ThreadContextStruct putResponseHeaders(Map<String, Set<String>> headers)
853863 return new ThreadContextStruct (requestHeaders , newResponseHeaders , transientHeaders , isSystemContext );
854864 }
855865
866+ private boolean hasTraceContext () {
867+ return requestHeaders .containsKey (Task .TRACE_PARENT_HTTP_HEADER )
868+ || requestHeaders .containsKey (Task .TRACE_STATE )
869+ || transientHeaders .containsKey (Task .APM_TRACE_CONTEXT );
870+ }
871+
872+ private boolean hasParentTraceContext () {
873+ return transientHeaders .containsKey (Task .PARENT_TRACE_PARENT_HEADER )
874+ || transientHeaders .containsKey (Task .PARENT_TRACE_STATE )
875+ || transientHeaders .containsKey (Task .PARENT_APM_TRACE_CONTEXT );
876+ }
877+
856878 private void logWarningHeaderThresholdExceeded (long threshold , Setting <?> thresholdSetting ) {
857879 // If available, log some selected headers to help identifying the source of the request.
858880 // Note: Only Task.HEADERS_TO_COPY are guaranteed to be preserved at this point.
0 commit comments