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

Add API for instrumenting FAAS and adjust the AWS plugin #3516

Merged
merged 9 commits into from
Mar 12, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
*/
package co.elastic.apm.agent.impl;

import co.elastic.apm.agent.bci.ElasticApmAgent;
import co.elastic.apm.agent.bci.IndyBootstrap;
import co.elastic.apm.agent.bci.InstrumentationStats;
import co.elastic.apm.agent.collections.WeakReferenceCountedMap;
import co.elastic.apm.agent.common.JvmRuntimeInfo;
import co.elastic.apm.agent.common.util.WildcardMatcher;
Expand All @@ -27,7 +29,12 @@
import co.elastic.apm.agent.configuration.MetricsConfiguration;
import co.elastic.apm.agent.configuration.ServerlessConfiguration;
import co.elastic.apm.agent.impl.error.RedactedException;
import co.elastic.apm.agent.impl.metadata.FaaSMetaDataExtension;
import co.elastic.apm.agent.impl.metadata.Framework;
import co.elastic.apm.agent.impl.metadata.MetaDataFuture;
import co.elastic.apm.agent.impl.metadata.NameAndIdField;
import co.elastic.apm.agent.impl.metadata.ServiceFactory;
import co.elastic.apm.agent.sdk.internal.util.LoggerUtils;
import co.elastic.apm.agent.tracer.service.Service;
import co.elastic.apm.agent.tracer.service.ServiceInfo;
import co.elastic.apm.agent.configuration.SpanConfiguration;
Expand All @@ -36,7 +43,6 @@
import co.elastic.apm.agent.impl.baggage.Baggage;
import co.elastic.apm.agent.impl.baggage.W3CBaggagePropagation;
import co.elastic.apm.agent.impl.error.ErrorCapture;
import co.elastic.apm.agent.impl.metadata.MetaDataFuture;
import co.elastic.apm.agent.impl.sampling.ProbabilitySampler;
import co.elastic.apm.agent.impl.sampling.Sampler;
import co.elastic.apm.agent.impl.stacktrace.StacktraceConfiguration;
Expand Down Expand Up @@ -83,6 +89,7 @@
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


/**
Expand All @@ -93,6 +100,7 @@
*/
public class ElasticApmTracer implements Tracer {
private static final Logger logger = LoggerFactory.getLogger(ElasticApmTracer.class);
private static final Logger enabledInstrumentationsLogger = LoggerUtils.logOnce(logger);

private static final WeakMap<ClassLoader, ServiceInfo> serviceInfoByClassLoader = WeakConcurrent.buildMap();

Expand Down Expand Up @@ -1007,4 +1015,33 @@ public Throwable redactExceptionIfRequired(@Nullable Throwable original) {
}
return original;
}

@Override
public void flush() {
long flushTimeout = configurationRegistry.getConfig(ServerlessConfiguration.class).getDataFlushTimeout();
try {
if (!reporter.flush(flushTimeout, TimeUnit.MILLISECONDS, true)) {
logger.error("APM data flush haven't completed within {} milliseconds.", flushTimeout);
}
} catch (Exception e) {
logger.error("An error occurred on flushing APM data.", e);
}
logEnabledInstrumentations();
}

private void logEnabledInstrumentations() {
if (enabledInstrumentationsLogger.isInfoEnabled()) {
InstrumentationStats instrumentationStats = ElasticApmAgent.getInstrumentationStats();
enabledInstrumentationsLogger.info("Used instrumentation groups: {}", instrumentationStats.getUsedInstrumentationGroups());
}
}

@Override
public void completeMetaData(String name, String version, String id, String region) {
metaDataFuture.getFaaSMetaDataExtensionFuture().complete(new FaaSMetaDataExtension(
new Framework(name, version),
new NameAndIdField(null, id),
region
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -175,13 +175,7 @@ public PotentiallyMultiValuedMap getFormUrlEncodedParameters() {
return postParams;
}

/**
* Adds a request header.
*
* @param headerName The name of the header.
* @param headerValue The value of the header.
* @return {@code this}, for fluent method chaining
*/
@Override
public Request addHeader(String headerName, @Nullable String headerValue) {
if (headerValue != null) {
headers.add(headerName, headerValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,11 @@ public Response withFinished(boolean finished) {
* @param headerValue The value of the header.
* @return {@code this}, for fluent method chaining
*/
public Response addHeader(String headerName, String headerValue) {
headers.add(headerName, headerValue);
@Override
public Response addHeader(String headerName, @Nullable String headerValue) {
if (headerValue != null) {
headers.add(headerName, headerValue);
}
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
* If a request originated from another service,
* the service origin interface can be used to collect information about the origin service.
*/
public class ServiceOrigin implements Recyclable {
public class ServiceOrigin implements co.elastic.apm.agent.tracer.ServiceOrigin, Recyclable {

@Nullable
private String id;
Expand All @@ -43,6 +43,7 @@ public String getId() {
return id;
}

@Override
public ServiceOrigin withId(@Nullable String id) {
this.id = id;
return this;
Expand All @@ -52,6 +53,7 @@ public StringBuilder getName() {
return name;
}

@Override
public ServiceOrigin withName(@Nullable CharSequence name) {
this.name.setLength(0);
if (name != null) {
Expand All @@ -72,6 +74,7 @@ public String getVersion() {
return version;
}

@Override
public ServiceOrigin withVersion(@Nullable String version) {
this.version = version;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ public CloudOrigin getCloudOrigin() {
return cloudOrigin;
}

@Override
public ServiceOrigin getServiceOrigin() {
return serviceOrigin;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

import javax.annotation.Nullable;

public class Faas implements Recyclable {
public class Faas implements co.elastic.apm.agent.tracer.Faas, Recyclable {

@Nullable
private String execution;
Expand Down Expand Up @@ -68,26 +68,31 @@ public String getVersion() {
return version;
}

@Override
public Faas withExecution(@Nullable String execution) {
this.execution = execution;
return this;
}

@Override
public Faas withColdStart(boolean coldStart) {
this.coldStart = coldStart;
return this;
}

@Override
public Faas withId(@Nullable String id) {
this.id = id;
return this;
}

@Override
public Faas withName(@Nullable String name) {
this.name = name;
return this;
}

@Override
public Faas withVersion(@Nullable String version) {
this.version = version;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

import javax.annotation.Nullable;

public class FaasTrigger implements Recyclable {
public class FaasTrigger implements co.elastic.apm.agent.tracer.FaasTrigger, Recyclable {

@Nullable
private String type;
Expand All @@ -40,11 +40,13 @@ public String getRequestId() {
return requestId;
}

@Override
public FaasTrigger withType(@Nullable String type) {
this.type = type;
return this;
}

@Override
public FaasTrigger withRequestId(@Nullable String requestId) {
this.requestId = requestId;
return this;
Expand Down
6 changes: 0 additions & 6 deletions apm-agent-plugins/apm-awslambda-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@
</properties>

<dependencies>
<!-- This plugin requires further refactoring to avoid agent dependencies. -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>apm-agent-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
*/
package co.elastic.apm.agent.awslambda;

import co.elastic.apm.agent.impl.ElasticApmTracer;
import co.elastic.apm.agent.sdk.ElasticApmInstrumentation;
import co.elastic.apm.agent.tracer.Tracer;
import co.elastic.apm.agent.tracer.configuration.ServerlessConfiguration;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
Expand All @@ -41,7 +41,7 @@ public abstract class AbstractAwsLambdaHandlerInstrumentation extends ElasticApm
@Nullable
protected String handlerMethodName;

public AbstractAwsLambdaHandlerInstrumentation(ElasticApmTracer tracer) {
public AbstractAwsLambdaHandlerInstrumentation(Tracer tracer) {
serverlessConfiguration = tracer.getConfig(ServerlessConfiguration.class);
String awsLambdaHandler = serverlessConfiguration.getAwsLambdaHandler();
//noinspection ConstantConditions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@

import co.elastic.apm.agent.awslambda.helper.AWSEventsHelper;
import co.elastic.apm.agent.awslambda.helper.PlainTransactionHelper;
import co.elastic.apm.agent.impl.ElasticApmTracer;
import co.elastic.apm.agent.impl.transaction.Transaction;
import co.elastic.apm.agent.tracer.Tracer;
import co.elastic.apm.agent.tracer.Transaction;
import com.amazonaws.services.lambda.runtime.Context;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
Expand All @@ -35,7 +35,7 @@

public class RequestHandlerInstrumentation extends AbstractAwsLambdaHandlerInstrumentation {

public RequestHandlerInstrumentation(ElasticApmTracer tracer) {
public RequestHandlerInstrumentation(Tracer tracer) {
super(tracer);
}

Expand Down Expand Up @@ -70,8 +70,8 @@ public static Object handlerEnter(@Nullable @Advice.Argument(value = 0) Object i
public static void handlerExit(@Nullable @Advice.Enter Object transactionObj,
@Nullable @Advice.Thrown Throwable thrown,
@Nullable @Advice.Return Object output) {
if (transactionObj instanceof Transaction) {
Transaction transaction = (Transaction) transactionObj;
if (transactionObj instanceof Transaction<?>) {
Transaction<?> transaction = (Transaction<?>) transactionObj;

if (output != null && output.getClass().getName().startsWith("com.amazonaws.services.lambda.runtime.events")) {
// handler uses aws events, it's safe to assume that the AWS events classes are available
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
package co.elastic.apm.agent.awslambda;

import co.elastic.apm.agent.awslambda.helper.PlainTransactionHelper;
import co.elastic.apm.agent.impl.ElasticApmTracer;
import co.elastic.apm.agent.impl.transaction.Transaction;
import co.elastic.apm.agent.tracer.Tracer;
import co.elastic.apm.agent.tracer.Transaction;
import com.amazonaws.services.lambda.runtime.Context;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
Expand All @@ -35,7 +35,7 @@

public class RequestStreamHandlerInstrumentation extends AbstractAwsLambdaHandlerInstrumentation {

public RequestStreamHandlerInstrumentation(ElasticApmTracer tracer) {
public RequestStreamHandlerInstrumentation(Tracer tracer) {
super(tracer);
}

Expand Down Expand Up @@ -65,8 +65,8 @@ public static Object handlerEnter(@Advice.Argument(value = 0) InputStream inputS
@Advice.OnMethodExit(suppress = Throwable.class, inline = false, onThrowable = Throwable.class)
public static void handlerExit(@Nullable @Advice.Enter Object transactionObj,
@Nullable @Advice.Thrown Throwable thrown) {
if (transactionObj instanceof Transaction) {
Transaction transaction = (Transaction) transactionObj;
if (transactionObj instanceof Transaction<?>) {
Transaction<?> transaction = (Transaction<?>) transactionObj;
PlainTransactionHelper.getInstance().finalizeTransaction(transaction, null, thrown);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
package co.elastic.apm.agent.awslambda.helper;

import co.elastic.apm.agent.awslambda.MapTextHeaderGetter;
import co.elastic.apm.agent.impl.ElasticApmTracer;
import co.elastic.apm.agent.tracer.GlobalTracer;
import co.elastic.apm.agent.impl.transaction.Transaction;
import co.elastic.apm.agent.sdk.internal.util.PrivilegedActionUtils;
import co.elastic.apm.agent.tracer.Tracer;
import co.elastic.apm.agent.tracer.Transaction;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
Expand All @@ -35,20 +35,20 @@ public class APIGatewayProxyV1TransactionHelper extends AbstractAPIGatewayTransa
@Nullable
private static APIGatewayProxyV1TransactionHelper INSTANCE;

private APIGatewayProxyV1TransactionHelper(ElasticApmTracer tracer) {
private APIGatewayProxyV1TransactionHelper(Tracer tracer) {
super(tracer);
}

public static APIGatewayProxyV1TransactionHelper getInstance() {
if (INSTANCE == null) {
INSTANCE = new APIGatewayProxyV1TransactionHelper(GlobalTracer.get().require(ElasticApmTracer.class));
INSTANCE = new APIGatewayProxyV1TransactionHelper(GlobalTracer.get());
}
return INSTANCE;
}

@Override
protected Transaction doStartTransaction(APIGatewayProxyRequestEvent apiGatewayEvent, Context lambdaContext) {
Transaction transaction = tracer.startChildTransaction(apiGatewayEvent.getHeaders(), MapTextHeaderGetter.INSTANCE, PrivilegedActionUtils.getClassLoader(apiGatewayEvent.getClass()));
protected Transaction<?> doStartTransaction(APIGatewayProxyRequestEvent apiGatewayEvent, Context lambdaContext) {
Transaction<?> transaction = tracer.startChildTransaction(apiGatewayEvent.getHeaders(), MapTextHeaderGetter.INSTANCE, PrivilegedActionUtils.getClassLoader(apiGatewayEvent.getClass()));
String host = getHost(apiGatewayEvent);

if (null != transaction) {
Expand Down Expand Up @@ -92,7 +92,7 @@ private String getQueryString(APIGatewayProxyRequestEvent apiGatewayEvent) {
}

@Override
public void captureOutputForTransaction(Transaction transaction, APIGatewayProxyResponseEvent responseEvent) {
public void captureOutputForTransaction(Transaction<?> transaction, APIGatewayProxyResponseEvent responseEvent) {
Integer statusCode = responseEvent.getStatusCode();
if (statusCode == null) {
statusCode = 0;
Expand All @@ -101,7 +101,7 @@ public void captureOutputForTransaction(Transaction transaction, APIGatewayProxy
}

@Override
protected void setTransactionTriggerData(Transaction transaction, APIGatewayProxyRequestEvent apiGatewayRequest) {
protected void setTransactionTriggerData(Transaction<?> transaction, APIGatewayProxyRequestEvent apiGatewayRequest) {
super.setTransactionTriggerData(transaction, apiGatewayRequest);
APIGatewayProxyRequestEvent.ProxyRequestContext rContext = apiGatewayRequest.getRequestContext();

Expand Down
Loading
Loading