-
Notifications
You must be signed in to change notification settings - Fork 867
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
Split lambda instrumentation into core and events #5326
Conversation
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.
Tried to explain some more interesting parts or large diffs in moved files
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.AwsLambdaFunctionInstrumenter; | ||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.AwsLambdaFunctionInstrumenterFactory; | ||
|
||
public final class AwsLambdaInstrumentationHelper { |
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.
Unchanged except for removing reference to SQS instrumenter
@Advice.Argument(1) Context context, | ||
@Advice.Local("otelInput") AwsLambdaRequest input, | ||
@Advice.Local("otelContext") io.opentelemetry.context.Context otelContext, | ||
@Advice.Local("otelScope") Scope otelScope) { |
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.
Unchanged except removing references to SQS instrumenter
|
||
final class LambdaParameters { | ||
|
||
static <T> Object[] toArray(Method targetMethod, T input, Context context) { |
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.
Removed mapper for core version of this util
* Returns the HTTP headers for the request extracted from the request handler's input. By | ||
* default, returns empty headers. | ||
*/ | ||
protected Map<String, String> extractHttpHeaders(I input) { |
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.
This is the most invasive change, since a handler that uses ApiGatewayProxyEvent would need to have its HTTP headers extracted. That being said, headers could be represented by input in other unknown ways so giving a hook into that could be considered generally useful (with limited practical use case).
if (noHttpPropagationNeeded()) { | ||
return new NoopRequest(source); | ||
} | ||
|
||
if (source.markSupported()) { | ||
return new MarkableApiGatewayProxyRequest(source); | ||
} | ||
// fallback | ||
return new CopiedApiGatewayProxyRequest(source); | ||
// It is known that the Lambda runtime passes ByteArrayInputStream's to functions, so gracefully |
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 believe this is reasonable. Notably, if we were actually hitting the fallback codepath, it would often be failing with ClassNotFoundException since commons-io is not referenced at all by lambda libraries and would only have to be available by luck
import io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal.AwsLambdaEventsInstrumenterFactory; | ||
import io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal.AwsLambdaSqsInstrumenterFactory; | ||
|
||
public final class AwsLambdaInstrumentationHelper { |
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.
Same as helper in current HEAD code
} | ||
|
||
@Override | ||
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() { |
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.
Added this matcher, verified by testInstrumentation in other project
@@ -63,18 +61,24 @@ public static void onEnter( | |||
@Advice.Local("otelMessageContext") io.opentelemetry.context.Context messageContext, | |||
@Advice.Local("otelMessageScope") Scope messageScope) { |
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.
This class is same as current instrumentation in HEAD
It's probably not enough to figure out a way to share logic in the advice classes between the two javaagent instrumentations at this time
super( | ||
openTelemetrySdk, | ||
WrapperConfiguration.flushTimeout(), | ||
AwsLambdaEventsInstrumenterFactory.createInstrumenter(openTelemetrySdk)); |
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.
Key change - the instrumenter factory in this module is aware of event objects
|
||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; | ||
import io.opentelemetry.api.OpenTelemetry; | ||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; | ||
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor; | ||
import io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaRequest; | ||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.AwsLambdaRequest; | ||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.AwsLambdaFunctionAttributesExtractor; |
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.
We use the core instrumentation logic, augmenting with event-specific logic
…-instrumentation into split-lambda
|
||
implementation("io.opentelemetry:opentelemetry-extension-aws") | ||
|
||
implementation("com.fasterxml.jackson.core:jackson-core") |
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 worth adding comment here (similar to your PR comment) since this is unusual
/** | ||
* This class is internal and is hence not for public use. Its APIs are unstable and can change at | ||
* any time. | ||
*/ |
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.
😄
compileOnly("commons-io:commons-io:2.2") | ||
compileOnly("org.slf4j:slf4j-api") | ||
|
||
implementation("com.fasterxml.jackson.core:jackson-databind") |
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.
and copy in comment here from your PR comment would be nice I think
implementation(project(":instrumentation:aws-lambda:aws-lambda-core-1.0:library")) | ||
|
||
implementation(project(":instrumentation:aws-lambda:aws-lambda-events-2.2:library")) { | ||
// Only needed by wrappers, not the javaagent. Muzzle will catch if we accidentally change this. |
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.
👍
* Split out lambda core instrumentation * More * Remove request wrapper from core * Split events * Dedupe * More * More renames * Finish * Clean * README * Rename more * Finish * Fix README * Fix README * Fix * Comments
Fixes #5325
Fixes #5285
Sorry for huge PR couldn't see a way to split up the PR since it's actually splitting up the code.
I had one big misunderstanding about the Java Lambda runtime, that it would include libraries like Jackson for our use. But it turns out unlike some other languages like Python, Java doesn't provide any libraries, presumably since Java provides good classloader isolation techniques.
This PR makes several changes
Splits instrumentation into two parts.
RequestStreamHandler
. Notably, most lambda functions which use an actual web framework built on top of Lambda (using aws-serverless-java-container or AWS's internal framework) only include this dependency and do not include -events nor should it need to. Core is mostly about instrumenting and does not contain features like serialization.RequestHandler
, including support for events. Because Lambda does not know about the user's function type when invoking our wrapper, we must reproduce Lambda's serialization logic when invoking the actual user function.Include Jackson as a dependency