-
Notifications
You must be signed in to change notification settings - Fork 325
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
Add APIs for manual inter process context propagation #396
Add APIs for manual inter process context propagation #396
Conversation
This is an alternative design to #394 It has a much nicer API geared towards Java 8 but also provides fallbacks for Java 7. For this to work on Java 7 we rely on the ability of a JVM to lazily link the method parameters so there is a small risk that on certain JVM implementations, the API does not work anymore for Java 7. |
59a45a5
to
460d71a
Compare
@kuisathaverat Pipeline Jenkins does not like that PR |
TLDR; adds these methods:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think instance methods are guaranteed not to be eagerly linked by all JVM implementations. This is what I found in https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.4:
a Java Virtual Machine implementation may choose to resolve each symbolic reference in a class or interface individually when it is used ("lazy" or "late" resolution), or to resolve them all at once when the class is being verified ("eager" or "static" resolution).
Maybe we can only rely on the class-separation you did with ElasticApm
- if we only want to inject context of active span we can use Tracer static method. Do you think making that a requirement is limiting? If we do that it would be safer, cleaner and even more similar to OpenTracing.
An even cleaner API would be usage of our interfaces instead of the Java 8 ones, and invoke the provided implementations through reflection in the actual tracer code, so to avoid dependency. You could even cache method handles based on implementation class name to significantly improve performance. Not as performant as method references as it also requires instance allocations, but much cleaner.
Other than that, maybe find a better word instead of stuck
for Java 7 users:)
* | ||
* When stuck on Java 7, just call ElasticApmJava7.startTransaction(). | ||
* Observation: actually, it also seems to work to call ElasticApm.startTransaction(). | ||
* I assume the JVM does not eagerly link the methods when only referring to static methods of the super class. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't rely on anything based on testing in this regard, only on the spec for everything that is JVM implementation dependent. I'd say Java 7 users should only use ElasticApmJava7
.
private static final ChildContextCreator<Map<String, ? extends Iterable<String>>> FROM_MAP = new ChildContextCreator<Map<String, ? extends Iterable<String>>>() { | ||
@Override | ||
public boolean asChildOf(TraceContext child, Map<String, ? extends Iterable<String>> headers) { | ||
final Iterator<String> iterator = headers.get(TRACE_PARENT_HEADER).iterator(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
headers.get(TRACE_PARENT_HEADER)
can produce null
- better to log that instead of throwing NPE
...m-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/ElasticApmApiInstrumentation.java
Show resolved
Hide resolved
@@ -160,6 +178,25 @@ public static TraceContext with128BitId() { | |||
return AS_ROOT; | |||
} | |||
|
|||
@IgnoreJRERequirement | |||
public static ChildContextCreator<Function<String, String>> fromHeaders() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Risky in Java 7
Codecov Report
@@ Coverage Diff @@
## master #396 +/- ##
============================================
- Coverage 72.26% 72.08% -0.19%
+ Complexity 1339 1314 -25
============================================
Files 145 144 -1
Lines 5257 5086 -171
Branches 549 523 -26
============================================
- Hits 3799 3666 -133
+ Misses 1222 1182 -40
- Partials 236 238 +2
Continue to review full report at Codecov.
|
Those can also be implemented via a lambda expression but don't have a Java 7/8 compatibility issue. The interfaces are invoked via a MethodHandle which is constructed in the API and read from method arguments in the instrumentation. Therefore, the instrumentation does not have to dynamically create MethodHandle or Method objects.
* on exceptions in that it ignores methods causing exceptions. | ||
* </p> | ||
*/ | ||
public enum FailSafeDeclaredMethodsCompiler implements MethodGraph.Compiler { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not actually needed for this change anymore but might still be relevant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent!!
Few comments and some leftovers from the former version.
...m-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/ElasticApmApiInstrumentation.java
Outdated
Show resolved
Hide resolved
* we eagerly resolve the parameters of all methods and exclude problematic methods. | ||
* </p> | ||
* <p> | ||
* One use case of this is to be able to instrument classes implementing {@code co.elastic.apm.api.Span}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a relevant use case anymore, but the use case I ran into of failing to instrument due to lookup restrictions in bootstrap CL is one, and the more common (I assume) is class that is loaded (and not yet linked) when its dependencies are not available in the classpath yet.
...m-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/ElasticApmApiInstrumentation.java
Show resolved
Hide resolved
...pm-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/AbstractSpanInstrumentation.java
Outdated
Show resolved
Hide resolved
...ugin/src/main/resources/META-INF/services/co.elastic.apm.agent.bci.ElasticApmInstrumentation
Outdated
Show resolved
Hide resolved
...m-api-plugin/src/main/java/co/elastic/apm/agent/plugin/api/ElasticApmApiInstrumentation.java
Outdated
Show resolved
Hide resolved
...lugins/apm-api-plugin/src/test/java/co/elastic/apm/api/ElasticApmApiInstrumentationTest.java
Show resolved
Hide resolved
* @since 1.3.0 | ||
*/ | ||
@Nonnull | ||
public static Transaction startTransactionWithRemoteParent(HeaderExtractor headerExtractor, HeadersExtractor headersExtractor) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think either replace this one to only accept HeadersExtractor
or add a third API method that accepts only that and uses the same private static
method with null
as the first argument
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
even for protocols which do support multiple headers, we want to have the ability to get a single value for a header in case we know it can only have a single value, like traceparent
.
closes #334