Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating Trace Context headers implementation #1024

Merged
merged 21 commits into from
Feb 14, 2020
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
83d5248
Refactoring- adding header set and get APIs
eyalkoren Feb 6, 2020
e19351a
Merge remote-tracking branch 'upstream/master' into tracestate-implem…
eyalkoren Feb 6, 2020
519a2c6
Merging AsyncHttpClient
eyalkoren Feb 6, 2020
2bf09df
Generics enhancements
eyalkoren Feb 6, 2020
66058db
More generics
felixbarny Feb 7, 2020
66bc6a2
Suggestion to improve Header*Bridge
felixbarny Feb 7, 2020
0433c7b
Remove HeaderGetter#getHeaders in favor of HeaderGetter#forEach
felixbarny Feb 7, 2020
d90e10b
Apply review suggestions
eyalkoren Feb 9, 2020
a0a86f9
Merge branch 'pull/1024' of git://github.com/felixbarny/apm-agent-jav…
eyalkoren Feb 9, 2020
31e7b84
minor adjustments
eyalkoren Feb 9, 2020
32bfb62
Merge branch 'felixbarny-pull/1024' into tracestate-implementation
eyalkoren Feb 9, 2020
c743932
Implement usage of the W3C traceparent header
eyalkoren Feb 9, 2020
2629e09
Update docs
eyalkoren Feb 9, 2020
95719a6
Implement tracestate header
eyalkoren Feb 9, 2020
6327508
Remove binary header when requested
eyalkoren Feb 10, 2020
e11b568
Remove debug prints
eyalkoren Feb 10, 2020
c284fc4
Merge remote-tracking branch 'upstream/master' into tracestate-implem…
eyalkoren Feb 10, 2020
d62f17c
Add tracestate to ArrayList(1) instead of appending to pooled StringB…
felixbarny Feb 13, 2020
568c15d
Fix HeadersExtractorBridge.Extractor
felixbarny Feb 14, 2020
c509c3e
Merge remote-tracking branch 'origin/master' into tracestate-implemen…
felixbarny Feb 14, 2020
756ad07
Add changelog, adjust added version to 1.14.0
felixbarny Feb 14, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
Expand All @@ -30,7 +30,6 @@
import co.elastic.apm.agent.impl.ElasticApmTracer;
import co.elastic.apm.agent.impl.transaction.AbstractSpan;
import co.elastic.apm.agent.impl.transaction.Span;
import co.elastic.apm.agent.impl.transaction.TraceContext;
import co.elastic.apm.agent.impl.transaction.TraceContextHolder;
import co.elastic.apm.agent.matcher.WildcardMatcher;
import net.bytebuddy.asm.Advice;
Expand Down Expand Up @@ -75,7 +74,7 @@ public static void onMethodEnter(@Advice.Origin Class<?> clazz,
if (tracer != null) {
final TraceContextHolder<?> parent = tracer.getActive();
if (parent == null) {
span = tracer.startTransaction(TraceContext.asRoot(), null, clazz.getClassLoader())
span = tracer.startRootTransaction(clazz.getClassLoader())
.withName(signature)
.activate();
} else if (parent.isSampled()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
Expand Down Expand Up @@ -485,6 +485,32 @@ public class CoreConfiguration extends ConfigurationOptionProvider {
"NOTE: this option can only be set via system properties, environment variables or the attacher options.")
.buildWithDefault(DEFAULT_CONFIG_FILE);

private final ConfigurationOption<Boolean> useElasticTraceparentHeader = ConfigurationOption.booleanOption()
.key("use_elastic_traceparent_header")
.tags("added[1.13.0]")
.configurationCategory(CORE_CATEGORY)
.description("To enable {apm-overview-ref-v}/distributed-tracing.html[distributed tracing], the agent\n" +
"adds trace context headers to outgoing requests (like HTTP requests, Kafka records, gRPC requests etc.).\n" +
"These headers (`traceparent` and `tracestate`) are defined in the\n" +
"https://www.w3.org/TR/trace-context-1/[W3C Trace Context] specification.\n" +
"\n" +
"When this setting is `true`, the agent will also add the header `elastic-apm-traceparent`\n" +
"for backwards compatibility with older versions of Elastic APM agents.")
.dynamic(true)
.buildWithDefault(true);

private final ConfigurationOption<Integer> tracestateHeaderSizeLimit = ConfigurationOption.integerOption()
.key("tracestate_header_size_limit")
felixbarny marked this conversation as resolved.
Show resolved Hide resolved
.tags("added[1.13.0]")
.configurationCategory(CORE_CATEGORY)
.description("The agent delegates the `tracestate` header, if received, as defined in the\n" +
"https://www.w3.org/TR/trace-context-1/[W3C Trace Context] specification.\n" +
"\n" +
"This setting limits the size of the `tracestate` header.")
.dynamic(true)
.tags("internal")
.buildWithDefault(4096);

public boolean isActive() {
return active.get();
}
Expand Down Expand Up @@ -605,6 +631,14 @@ public boolean isBreakdownMetricsEnabled() {
return breakdownMetrics.get();
}

public boolean isElasticTraceparentHeaderEnabled() {
return useElasticTraceparentHeader.get();
}

public int getTracestateSizeLimit() {
return tracestateHeaderSizeLimit.get();
}

/*
* Makes sure to not initialize ConfigurationOption, which would initialize the logger
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@
import co.elastic.apm.agent.impl.sampling.Sampler;
import co.elastic.apm.agent.impl.stacktrace.StacktraceConfiguration;
import co.elastic.apm.agent.impl.transaction.AbstractSpan;
import co.elastic.apm.agent.impl.transaction.BinaryHeaderGetter;
import co.elastic.apm.agent.impl.transaction.HeaderGetter;
import co.elastic.apm.agent.impl.transaction.Span;
import co.elastic.apm.agent.impl.transaction.TextHeaderGetter;
import co.elastic.apm.agent.impl.transaction.TraceContext;
import co.elastic.apm.agent.impl.transaction.TraceContextHolder;
import co.elastic.apm.agent.impl.transaction.Transaction;
Expand Down Expand Up @@ -149,60 +152,119 @@ public void onChange(ConfigurationOption<?> configurationOption, Double oldValue
reporter.scheduleMetricReporting(metricRegistry, configurationRegistry.getConfig(ReporterConfiguration.class).getMetricsIntervalMs());

// sets the assertionsEnabled flag to true if indeed enabled
//noinspection AssertWithSideEffects
assert assertionsEnabled = true;
}

public <T> Transaction startRootTransaction(@Nullable ClassLoader initiatingClassLoader) {
return startTransaction(TraceContext.asRoot(), null, initiatingClassLoader);
/**
* Starts a trace-root transaction
*
* @param initiatingClassLoader the class loader corresponding to the service which initiated the creation of the transaction.
* Used to determine the service name.
* @return a transaction which is a child of the provided parent
*/
public Transaction startRootTransaction(@Nullable ClassLoader initiatingClassLoader) {
return startRootTransaction(sampler, -1, initiatingClassLoader);
}

/**
* Starts a transaction as a child of the provided parent
* Starts a trace-root transaction with a specified sampler and start timestamp
*
* @param childContextCreator used to make the transaction a child of the provided parent
* @param parent the parent of the transaction. May be a traceparent header.
* @param sampler the {@link Sampler} instance which is responsible for determining the sampling decision if this is a root transaction
* @param epochMicros the start timestamp
* @param initiatingClassLoader the class loader corresponding to the service which initiated the creation of the transaction.
* Used to determine the service name.
* @param <T> the type of the parent. {@code String} in case of a traceparent header.
* Used to determine the service name and to load application-scoped classes like the {@link org.slf4j.MDC},
* for log correlation.
* @return a transaction which is a child of the provided parent
*/
public <T> Transaction startTransaction(TraceContext.ChildContextCreator<T> childContextCreator, @Nullable T parent, @Nullable ClassLoader initiatingClassLoader) {
return startTransaction(childContextCreator, parent, sampler, -1, initiatingClassLoader);
public Transaction startRootTransaction(Sampler sampler, long epochMicros, @Nullable ClassLoader initiatingClassLoader) {
Transaction transaction;
if (!coreConfiguration.isActive()) {
transaction = noopTransaction();
} else {
transaction = createTransaction().start(TraceContext.asRoot(), null, epochMicros, sampler, initiatingClassLoader);
}
afterTransactionStart(initiatingClassLoader, transaction);
return transaction;
}

public void avoidWrappingOnThread() {
allowWrappingOnThread.set(Boolean.FALSE);
/**
* Starts a transaction as a child of the context headers obtained through the provided {@link HeaderGetter}
*
* @param headerCarrier the Object from which context headers can be obtained, typically a request or a message
* @param textHeadersGetter provides the trace context headers required in order to create a child transaction
* @param initiatingClassLoader the class loader corresponding to the service which initiated the creation of the transaction.
* Used to determine the service name.
* @return a transaction which is a child of the provided parent
*/
public <C> Transaction startChildTransaction(@Nullable C headerCarrier, TextHeaderGetter<C> textHeadersGetter, @Nullable ClassLoader initiatingClassLoader) {
return startChildTransaction(headerCarrier, textHeadersGetter, sampler, -1, initiatingClassLoader);
}

public void allowWrappingOnThread() {
allowWrappingOnThread.set(Boolean.TRUE);
/**
* Starts a transaction as a child of the context headers obtained through the provided {@link HeaderGetter}
*
* @param headerCarrier the Object from which context headers can be obtained, typically a request or a message
* @param textHeadersGetter provides the trace context headers required in order to create a child transaction
* @param sampler the {@link Sampler} instance which is responsible for determining the sampling decision if this is a root transaction
* @param epochMicros the start timestamp
* @param initiatingClassLoader the class loader corresponding to the service which initiated the creation of the transaction.
* Used to determine the service name and to load application-scoped classes like the {@link org.slf4j.MDC},
* for log correlation.
* @return a transaction which is a child of the provided parent
*/
public <C> Transaction startChildTransaction(@Nullable C headerCarrier, TextHeaderGetter<C> textHeadersGetter, Sampler sampler,
long epochMicros, @Nullable ClassLoader initiatingClassLoader) {
Transaction transaction;
if (!coreConfiguration.isActive()) {
transaction = noopTransaction();
} else {
transaction = createTransaction().start(TraceContext.<C>getFromTraceContextTextHeaders(), headerCarrier,
textHeadersGetter, epochMicros, sampler, initiatingClassLoader);
}
afterTransactionStart(initiatingClassLoader, transaction);
return transaction;
}

public boolean isWrappingAllowedOnThread() {
return allowWrappingOnThread.get() == Boolean.TRUE;
/**
* Starts a transaction as a child of the context headers obtained through the provided {@link HeaderGetter}
*
* @param headerCarrier the Object from which context headers can be obtained, typically a request or a message
* @param binaryHeadersGetter provides the trace context headers required in order to create a child transaction
* @param initiatingClassLoader the class loader corresponding to the service which initiated the creation of the transaction.
* Used to determine the service name.
* @return a transaction which is a child of the provided parent
*/
public <C> Transaction startChildTransaction(@Nullable C headerCarrier, BinaryHeaderGetter<C> binaryHeadersGetter, @Nullable ClassLoader initiatingClassLoader) {
return startChildTransaction(headerCarrier, binaryHeadersGetter, sampler, -1, initiatingClassLoader);
}

/**
* Starts a transaction as a child of the provided parent
* Starts a transaction as a child of the context headers obtained through the provided {@link HeaderGetter}
*
* @param childContextCreator used to make the transaction a child of the provided parent
* @param parent the parent of the transaction. May be a traceparent header.
* @param headerCarrier the Object from which context headers can be obtained, typically a request or a message
* @param binaryHeadersGetter provides the trace context headers required in order to create a child transaction
* @param sampler the {@link Sampler} instance which is responsible for determining the sampling decision if this is a root transaction
* @param epochMicros the start timestamp
* @param initiatingClassLoader the class loader corresponding to the service which initiated the creation of the transaction.
* Used to determine the service name and to load application-scoped classes like the {@link org.slf4j.MDC},
* for log correlation.
* @param <T> the type of the parent. {@code String} in case of a traceparent header.
* @return a transaction which is a child of the provided parent
*/
public <T> Transaction startTransaction(TraceContext.ChildContextCreator<T> childContextCreator, @Nullable T parent, Sampler sampler,
long epochMicros, @Nullable ClassLoader initiatingClassLoader) {
public <C> Transaction startChildTransaction(@Nullable C headerCarrier, BinaryHeaderGetter<C> binaryHeadersGetter,
Sampler sampler, long epochMicros, @Nullable ClassLoader initiatingClassLoader) {
Transaction transaction;
if (!coreConfiguration.isActive()) {
transaction = noopTransaction();
} else {
transaction = createTransaction().start(childContextCreator, parent, epochMicros, sampler, initiatingClassLoader);
transaction = createTransaction().start(TraceContext.<C>getFromTraceContextBinaryHeaders(), headerCarrier,
binaryHeadersGetter, epochMicros, sampler, initiatingClassLoader);
}
afterTransactionStart(initiatingClassLoader, transaction);
return transaction;
}

private void afterTransactionStart(@Nullable ClassLoader initiatingClassLoader, Transaction transaction) {
if (logger.isDebugEnabled()) {
logger.debug("startTransaction {} {", transaction);
if (logger.isTraceEnabled()) {
Expand All @@ -214,7 +276,18 @@ public <T> Transaction startTransaction(TraceContext.ChildContextCreator<T> chil
if (serviceName != null) {
transaction.getTraceContext().setServiceName(serviceName);
}
return transaction;
}

public void avoidWrappingOnThread() {
allowWrappingOnThread.set(Boolean.FALSE);
}

public void allowWrappingOnThread() {
allowWrappingOnThread.set(Boolean.TRUE);
}

public boolean isWrappingAllowedOnThread() {
return allowWrappingOnThread.get() == Boolean.TRUE;
}

public Transaction noopTransaction() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
Expand All @@ -37,7 +37,6 @@

public class Message implements Recyclable {

@SuppressWarnings({"Convert2Diamond", "Convert2Lambda", "Anonymous2MethodRef"})
private static final ObjectPool<StringBuilder> stringBuilderPool = QueueBasedObjectPool.of(new MpmcAtomicArrayQueue<StringBuilder>(128), false,
new Allocator<StringBuilder>() {
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*-
* #%L
* Elastic APM Java agent
* %%
* Copyright (C) 2018 - 2020 Elastic and contributors
* %%
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* #L%
*/
package co.elastic.apm.agent.impl.transaction;

public abstract class AbstractHeaderGetter<T, C> implements HeaderGetter<T, C> {
@Override
public <S> void forEach(String headerName, C carrier, S state, HeaderConsumer<T, S> consumer) {
T firstHeader = getFirstHeader(headerName, carrier);
if (firstHeader != null) {
consumer.accept(firstHeader, state);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*-
* #%L
* Elastic APM Java agent
* %%
* Copyright (C) 2018 - 2020 Elastic and contributors
* %%
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* #L%
*/
package co.elastic.apm.agent.impl.transaction;

public interface BinaryHeaderGetter<C> extends HeaderGetter<byte[], C> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*-
* #%L
* Elastic APM Java agent
* %%
* Copyright (C) 2018 - 2020 Elastic and contributors
* %%
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* #L%
*/
package co.elastic.apm.agent.impl.transaction;

import javax.annotation.Nullable;

public interface BinaryHeaderSetter<C> extends HeaderSetter<byte[], C> {

/**
* Since the implementation itself knows the intrinsics of the headers and carrier lifecycle and handling, it should
* be responsible for providing a byte array. This enables the implementation to cache byte arrays wherever required
* and possible.
* <p>
* NOTE: if this method returns null, the tracer will allocate a buffer for each header.
*
* @param headerName the header name for which the byte array is required
* @param length the length of the required byte array
* @return a byte array with the requested length, or null if header-value-buffer is not supported.
*/
@Nullable
byte[] getFixedLengthByteArray(String headerName, int length);
}
Loading