Public APIedit

The public API of the Elastic APM Java agent lets you customize and manually create spans and transactions, as well as track errors.

The first step in getting started with the API is to declare a dependency to the API:

pom.xml. 

<dependency>
    <groupId>co.elastic.apm</groupId>
    <artifactId>apm-agent-api</artifactId>
    <version>${elastic-apm.version}</version>
</dependency>

build.gradle. 

compile "co.elastic.apm:apm-agent-api:$elasticApmVersion"

Replace the version placeholders with the latest version from maven central: Maven Central

Tracer APIedit

The tracer gives you access to the currently active transaction and span. It can also be used to track an exception.

To use the API, you can just invoke the static methods on the class co.elastic.apm.api.ElasticApm.

Transaction currentTransaction()edit

Returns the currently active transaction. See Transaction APIedit on how to customize the current transaction.

If there is no current transaction, this method will return a noop transaction, which means that you never have to check for null values.

import co.elastic.apm.api.ElasticApm;
import co.elastic.apm.api.Transaction;

Transaction transaction = ElasticApm.currentTransaction();
Note

Transactions created via ElasticApm.startTransaction() can not be retrieved by calling this method. See span.activate() on how to achieve that.

Span currentSpan()edit

Returns the currently active span or transaction. See Span APIedit on how to customize the current span.

If there is no current span, this method will return a noop span, which means that you never have to check for null values.

Note that even if this method is returning a noop span, you can still capture exceptions on it. These exceptions will not have a link to a Span or a Transaction.

import co.elastic.apm.api.ElasticApm;
import co.elastic.apm.api.Span;

Span span = ElasticApm.currentSpan();
Note

Spans created via createSpan() can not be retrieved by calling this method. See span.activate() on how to achieve that.

Transaction startTransaction()edit

Use this method to create a custom transaction.

Note that the agent will do this for you automatically when ever your application receives an incoming HTTP request. You only need to use this method to create custom transactions.

It is important to call void end()edit when the transaction has ended. A best practice is to use the transaction in a try-catch-finally block. Example:

Transaction transaction = ElasticApm.startTransaction();
try {
    transaction.setName("MyController#myAction");
    transaction.setType(Transaction.TYPE_REQUEST);
    // do your thing...
} catch (Exception e) {
    transaction.captureException(e);
    throw e;
} finally {
    transaction.end();
}
Note

Transactions created via this method can not be retrieved by calling ElasticApm.currentSpan() or ElasticApm.currentTransaction(). See transaction.activate() on how to achieve that.

Annotation APIedit

The API comes with two annotations which make it easier to create custom spans and transactions. Just put the annotations on top of your methods and the agent will take care of creating and reporting the corresponding transaction and spans. It will also make sure to capture any uncaught exceptions.

Note

It is required to configure the application_packagesedit, otherwise these annotations will be ignored.

@CaptureTransactionedit

Annotating a method with @CaptureTransaction creates a transaction for that method.

Note that this only works when there is no active transaction on the same thread.

  • value: The name of the span. Defaults to ClassName#methodName
  • type: The type of the transaction. Defaults to request

@CaptureSpanedit

Annotating a method with @CaptureSpan creates a span as the child of the currently active span or transaction (Span currentSpan()edit).

When there is no current span, no span will be created.

  • value: The name of the span. Defaults to ClassName#methodName
  • type: The type of the span. Defaults to app

Transaction APIedit

A transaction is the data captured by an agent representing an event occurring in a monitored service and groups multiple spans in a logical group. A transaction is the first Span of a service, and is also known under the term entry span.

See Transaction currentTransaction()edit on how to get a reference of the current transaction.

Transaction is a sub-type of Span. So it has all the methods a Span offers plus additional ones.

Note

Calling any of the transaction’s methods after void end()edit has been called is illegal. You may only interact with transaction when you have control over its lifecycle. For example, if a span is ended in another thread you must not add tags if there is a chance for a race between the void end()edit and the void addTag(String key, String value)edit method.

void setName(String name)edit

Override the name of the current transaction. For supported frameworks, the transaction name is determined automatically, and can be overridden using this method.

Example:

transaction.setName("My Transaction");
  • name: (required) A string describing name of the transaction

void setType(String type)edit

Sets the type of the transaction. There’s a special type called request, which is used by the agent for the transactions automatically created when an incoming HTTP request is detected.

Example:

transaction.setType(Transaction.TYPE_REQUEST);
  • type: The type of the transaction

void addTag(String key, String value)edit

A flat mapping of user-defined tags with string values. Note: the tags are indexed in Elasticsearch so that they are searchable and aggregatable. By all means, you should avoid that user specified data, like URL parameters, is used as a tag key as it can lead to mapping explosions.

transaction.setTag("foo", "bar");
  • key: The tag key
  • value: The tag value

void setUser(String id, String email, String username)edit

Call this to enrich collected performance data and errors with information about the user/client. This method can be called at any point during the request/response life cycle (i.e. while a transaction is active). The given context will be added to the active transaction.

If an error is captured, the context from the active transaction is used as context for the captured error.

transaction.setUser(user.getId(), user.getEmail(), user.getUsername());
  • id: The user’s id or null, if not applicable.
  • email: The user’s email address or null, if not applicable.
  • username: The user’s name or null, if not applicable.

void captureException(Exception e)edit

Captures an exception and reports it to the APM server.

String getId()edit

Returns the id of this transaction (never null)

If this transaction represents a noop, this method returns an empty string.

String getTraceId()edit

Returns the trace-id of this transaction.

The trace-id is consistent across all transactions and spans which belong to the same logical trace, even for transactions and spans which happened in another service (given this service is also monitored by Elastic APM).

If this span represents a noop, this method returns an empty string.

String ensureParentId()edit

If the transaction does not have a parent-ID yet, calling this method generates a new ID, sets it as the parent-ID of this transaction, and returns it as a String.

This enables the correlation of the spans the JavaScript Real User Monitoring (RUM) agent creates for the initial page load with the transaction of the backend service. If your backend service generates the HTML page dynamically, initializing the JavaScript RUM agent with the value of this method allows analyzing the time spent in the browser vs in the backend services.

To enable the JavaScript RUM agent when using an HTML templating language like Freemarker, add ElasticApm.currentTransaction() with the key "transaction" to the model.

Also, add a snippet similar to this to the body of your HTML page, preferably before other JS libraries:

<script src="elastic-apm-js-base/dist/bundles/elastic-apm-js-base.umd.min.js"></script>
<script>
  elasticApm.init({
    serviceName: "service-name",
    serverUrl: "http://localhost:8200",
    pageLoadTraceId: "${transaction.traceId}",
    pageLoadSpanId: "${transaction.ensureParentId()}",
    pageLoadSampled: ${transaction.sampled}
  })
</script>

See the JavaScript RUM agent documentation for more information.

Span createSpan()edit

Start and return a new custom span as a child of this transaction.

It is important to call void end()edit when the span has ended. A best practice is to use the span in a try-catch-finally block. Example:

Span span = parent.createSpan();
try {
    span.setName("SELECT FROM customer");
    span.setType("db.mysql.query");
    // do your thing...
} catch (Exception e) {
    ElasticApm.captureException(e);
    throw e;
} finally {
    span.end();
}
Note

Spans created via this method can not be retrieved by calling ElasticApm.currentSpan().

void setResult(String result)edit

A string describing the result of the transaction. This is typically the HTTP status code, or e.g. "success" for a background task

  • result: a string describing the result of the transaction

void end()edit

Ends the transaction and schedules it to be reported to the APM Server. It is illegal to call any methods on a span instance which has already ended. This also includes this method and Span createSpan()edit. Example:

transaction.end();

Scope activate()edit

Makes this span the active span on the current thread until Scope#close() has been called. Scopes should only be used in try-with-resource statements in order to make sure the Scope#close() method is called in all circumstances. Failing to close a scope can lead to memory leaks and corrupts the parent-child relationships.

This method should always be used within a try-with-resources statement:

Transaction transaction = ElasticApm.startTransaction();
// Within the try block the transaction is available
// on the current thread via ElasticApm.currentTransaction().
// This is also true for methods called within the try block.
try (final Scope scope = transaction.activate()) {
    transaction.setName("MyController#myAction");
    transaction.setType(Transaction.TYPE_REQUEST);
    // do your thing...
} catch (Exception e) {
    transaction.captureException(e);
    throw e;
} finally {
    transaction.end();
}
Note

Scope activate()edit and Scope#close() have to be called on the same thread.

boolean isSampled()edit

Returns true if this transaction is recorded and sent to the APM Server

Span APIedit

A span contains information about a specific code path, executed as part of a transaction.

If for example a database query happens within a recorded transaction, a span representing this database query may be created. In such a case the name of the span will contain information about the query itself, and the type will hold information about the database type.

See Span currentSpan()edit on how to get a reference of the current span.

void setName(String name)edit

Override the name of the current span.

Example:

span.setName("SELECT FROM customer");
  • name: the name of the span

void setType(String type)edit

Sets the type of span. The type is a hierarchical string used to group similar spans together. For instance, all spans of MySQL queries are given the type db.mysql.query.

In the above example db is considered the type prefix. Though there are no naming restrictions for this prefix, the following are standardized across all Elastic APM agents: app, db, cache, template, and ext.

  • type: the type of the span

void addTag(String key, String value)edit

A flat mapping of user-defined tags with string values. Note: the tags are indexed in Elasticsearch so that they are searchable and aggregatable. By all means, you should avoid that user specified data, like URL parameters, is used as a tag key as it can lead to mapping explosions.

span.setTag("foo", "bar");
  • key: The tag key
  • value: The tag value

void captureException(Exception e)edit

Captures an exception and reports it to the APM server.

String getId()edit

Returns the id of this span (never null)

If this span represents a noop, this method returns an empty string.

String getTraceId()edit

Returns the trace-ID of this span.

The trace-ID is consistent across all transactions and spans which belong to the same logical trace, even for transactions and spans which happened in another service (given this service is also monitored by Elastic APM).

If this span represents a noop, this method returns an empty string.

void end()edit

Ends the span and schedules it to be reported to the APM Server. It is illegal to call any methods on a span instance which has already ended. This also includes this method and Span createSpan()edit.

Span createSpan()edit

Start and return a new custom span as a child of this span.

It is important to call void end()edit when the span has ended. A best practice is to use the span in a try-catch-finally block. Example:

Span span = parent.createSpan();
try {
    span.setName("SELECT FROM customer");
    span.setType("db.mysql.query");
    // do your thing...
} catch (Exception e) {
    span.captureException(e);
    throw e;
} finally {
    span.end();
}
Note

Spans created via this method can not be retrieved by calling ElasticApm.currentSpan(). See span.activate() on how to achieve that.

Scope activate()edit

Makes this span the active span on the current thread until Scope#close() has been called. Scopes should only be used in try-with-resource statements in order to make sure the Scope#close() method is called in all circumstances. Failing to close a scope can lead to memory leaks and corrupts the parent-child relationships.

This method should always be used within a try-with-resources statement:

Span span = parent.startSpan();
// Within the try block the span is available
// on the current thread via ElasticApm.currentSpan().
// This is also true for methods called within the try block.
try (final Scope scope = span.activate()) {
    span.setName("SELECT FROM customer");
    span.setType("db.mysql.query");
    // do your thing...
} catch (Exception e) {
    span.captureException(e);
    throw e;
} finally {
    span.end();
}
Note

Calling any of the span’s methods after void end()edit has been called is illegal. You may only interact with span when you have control over its lifecycle. For example, if a span is ended in another thread you must not add tags if there is a chance for a race between the void end()edit and the void addTag(String key, String value)edit method.

boolean isSampled()edit

Returns true if this span is recorded and sent to the APM Server