Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -24,6 +24,7 @@
import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext;
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
import datadog.trace.bootstrap.instrumentation.api.InternalSpanTypes;
import datadog.trace.bootstrap.instrumentation.api.ResourceNamePriorities;
import datadog.trace.config.inversion.ConfigHelper;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
Expand Down Expand Up @@ -126,6 +127,21 @@ static void exit(
String lambdaRequestId = awsContext.getAwsRequestId();

AgentTracer.get().notifyAppSecEnd(span);
// Force the resource name back to the literal placeholder marker right
// before finish so that the Datadog Lambda Extension's filter
// (filter_span_from_lambda_library_or_runtime in
// bottlecap/src/traces/trace_processor.rs, which compares
// span.resource == "dd-tracer-serverless-span") drops the placeholder.
// Other instrumentation (HTTP/JAX-RS) may have overwritten it with the
// route ("POST /") during the invocation, in which case the extension
// would fail to dedup, leading to the placeholder leaking to the backend
// with parent_id=0 and detaching the inferred apigateway root from the
// rest of the trace.
// Use TAG_INTERCEPTOR priority because DDSpanContext.setResourceName
// ignores writes whose priority is below the current resource priority,
// and the HTTP/JAX-RS instrumentation will already have written
// HTTP_FRAMEWORK_ROUTE (3) by this point.
span.setResourceName(INVOCATION_SPAN_NAME, ResourceNamePriorities.TAG_INTERCEPTOR);
span.finish();
AgentTracer.get().notifyExtensionEnd(span, result, null != throwable, lambdaRequestId);
} finally {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
import datadog.trace.bootstrap.instrumentation.api.ResourceNamePriorities;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
* Simulates HTTP server instrumentation updating the local root span resource (e.g. route) while
* the Lambda invocation span is active.
*/
public class HandlerStreamingSimulatesHttpFrameworkResource implements RequestStreamHandler {

@Override
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
throws IOException {
AgentSpan span = AgentTracer.activeSpan();
if (span != null) {
span.setResourceName("POST /api/simulated", ResourceNamePriorities.HTTP_FRAMEWORK_ROUTE);
}
outputStream.write('O');
outputStream.write('K');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,28 @@ abstract class LambdaHandlerInstrumentationTest extends VersionedNamingTestBase
}
}

def "serverless invocation span resource reset after simulated HTTP framework overwrite"() {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Move the new coverage to JUnit 5

This adds a new Spock feature method to the existing Groovy spec, but /workspace/dd-trace-java/AGENTS.md explicitly says new tests should always use JUnit 5 and not add new Groovy/Spock tests, migrating the existing Groovy test when touched. Keeping this coverage here extends the test framework the repo is trying to retire, so please move the new case to a JUnit 5 test instead of adding another Spock method.

Useful? React with 👍 / 👎.

when:
def input = new ByteArrayInputStream(StandardCharsets.UTF_8.encode("Hello").array())
def output = new ByteArrayOutputStream()
def ctx = Stub(Context) {
getAwsRequestId() >> requestId
}
new HandlerStreamingSimulatesHttpFrameworkResource().handleRequest(input, output, ctx)

then:
assertTraces(1) {
trace(1) {
span {
operationName operation()
resourceName operation()
spanType DDSpanTypes.SERVERLESS
errored false
}
}
}
}

def "test streaming handler with error"() {
when:
def input = new ByteArrayInputStream(StandardCharsets.UTF_8.encode("Hello").array())
Expand Down
Loading