Java performance integration guide

Step-by-step instructions for adding performance monitoring and distributed tracing to your Java projects.

BugSnag’s serverside performance monitoring leverages OpenTelemetry. With the wealth of open source OpenTelemetry instrumentation available for Java, you can easily send spans and traces from your service to BugSnag by installing the OpenTelemetry SDK and completing some simple configuration.

This guide provides a simple way to get traces sent to BugSnag. The OpenTelemetry ecosystem allows for many different configurations. See the Advanced capabilities section for more details.

Automatic instrumentation

The easiest way to get your app instrumented is to use the OpenTelemetry Java Agent to automatically instrument your app. You may wish to consider using OpenTelemetry’s Spring Boot starter in certain situations, such as for Spring Boot Native apps, where the Java Agent does not work.

Automatic instrumentation installation

To automatically instrument your Java app in this way, download the Java Agent from the opentelemetry-java-instrumentation repository:

curl -L -O https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar

Make a note of the download path as you will use this again later.

Automatic instrumentation configuration

Next you need to set some configuration:

export JAVA_TOOL_OPTIONS="-javaagent:<PATH_TO_DOWNLOADED_JAVA_AGENT>" \
  OTEL_EXPORTER_OTLP_ENDPOINT=https://<PROJECT_API_KEY>.otlp.bugsnag.com:4318 \
  OTEL_SERVICE_NAME="your-service-name" \
  OTEL_RESOURCE_ATTRIBUTES="deployment.environment=<RELEASE_STAGE>,service.version=<APP_VERSION>" \
  OTEL_METRICS_EXPORTER=none \
  OTEL_LOGS_EXPORTER=none
  • <PATH_TO_DOWNLOADED_JAVA_AGENT> is the OTel Java Agent download path from the first step.

  • <PROJECT_API_KEY> can be found in project settings in the BugSnag dashboard.

  • OTEL_SERVICE_NAME should uniquely identify your service. We recommend using the same name as your project name.

  • <RELEASE_STAGE> and <APP_VERSION> must be the same as you are passing to your BugSnag Error SDK. They are case sensitive.

For the full list of configuration options, see the automatic configuration page in the OpenTelemetry documentation.

Finally, running your app will start sending span information to BugSnag.

Custom spans

For higher resolution information into the performance of your application, you can create your own spans whenever you like. To do this, get a tracer:

import io.opentelemetry.api.GlobalOpenTelemetry;


Tracer tracer = GlobalOpenTelemetry.getTracer("application");

Then wrap some work in a span:

Span span = tracer.spanBuilder("some interesting work")
    .startSpan();

try (Scope scope = span.makeCurrent()) {
    // some interesting work
} catch (Throwable t) {
    span.recordException(t);
} finally {
    span.end();
}

For more information see the Java OpenTelemetry instrumentation documentation.

If you would like BugSnag to aggregate your custom span to provide you with summary statistics on its performance, then you need to set a bugsnag.span.first_class attribute on the span. BugSnag will then automatically create a grouping for that span based on its name. This will appear under the ‘Custom Spans’ tab of your Performance dashboard.

span.setAttribute("bugsnag.span.first_class", true);

Manual instrumentation

If you would prefer to have more visibility and control over what instrumentation is being added, you can configure instrumentation in code. To do this see the OpenTelemetry Manual Instrumentation guide.

Advanced capabilities

The above guide should allow you to get started with BugSnag Performance quickly. The OpenTelemetry ecosystem has a huge range of possibilities for different capabilites. To find out about the possibilities please browse the OpenTelemetry documentation for Java.

We will explore a few topics briefly here:

Sampling

Spans sent from OpenTelemetry SDKs use up your unmanaged quota. No spans will be ingested by BugSnag once your daily quota is exhausted. To ensure you have span coverage throughout the day, we recommend you use sampling.

By default the OpenTelemetry SDK will use the parentbased_always_on sampler, which will sample according to the sample decision from the incoming network request if there is one, and always sample if there is not. To use this requires clients of your Java server be instrumented in such a way that they pass their sampling information.

To apply a fixed sampling rate to all your Java spans, you can use the traceidratio sampler:

export OTEL_TRACES_SAMPLER="traceidratio"
export OTEL_TRACES_SAMPLER_ARG="0.25" # this will cause 25% of your traces to be sampled

gradle appRun # your usual app start command

Alternatively you can use the parentbased_traceidratio sampler. This will sample at a constant rate, unless the trace context was propagated from a client, in which case it will use the same sample decision that the client used:

export OTEL_TRACES_SAMPLER="parentbased_traceidratio"
export OTEL_TRACES_SAMPLER_ARG="0.25" # this will cause 25% of those traces that did not start in a client to be sampled

gradle appRun # your usual app start command

The BugSnag Performance SDKs (for Android, iOS, React Native, Flutter and Unity) can be configured to propagate trace context and sampling decisions to assist with distributed tracing. Read our Distributed Tracing documentation for more information.

Wire protocol

Traces can be received by BugSnag via either gRPC or HTTP (protobuf or JSON). In most cases the simplest way to send traces to BugSnag is to export an environment variable with your BugSnag project’s dedicated OpenTelemetry endpoint before running your OpenTelemetry instrumented app:

export OTEL_EXPORTER_OTLP_PROTOCOL="grpc"
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://<PROJECT_API_KEY>.otlp.bugsnag.com:4317"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://<PROJECT_API_KEY>.otlp.bugsnag.com:4318/v1/traces"

For more configuration options see the OpenTelemetry OTLP Exporter Configuration documentation.

Collector

An OpenTelemetry Collector is an open source component that OpenTelemetry users can host on their own infrastructure. It can receive telemetry data from multiple sources, process it in various ways, and send it on to multiple telemetry back-ends, including BugSnag.

An important use of Collectors is to enable tail-based sampling, where a trace can be inspected in its entirety before making a sampling decision, for example looking to see whether it contained any errors.

To find out more about the Collector itself, see the OpenTelemetry Collector documentation.

To learn about using a collector with BugSnag, see our dedicated page on using a collector.

Span batch size

The maximum payload size for BugSnag’s OpenTelemetry trace endpoints is 1MB. OpenTelemetry payload sizes can be controlled via the batch size in the SDK or collector configuration.

The appropriate batch size will largely depend on the number of attributes getting added to your spans and therefore you may need to experiment to find the appropriate setting. The batch size can be controlled by setting an environment variable; we generally recommend 200 as a good starting point, which is lower than the default of 512 spans per batch.

export OTEL_BSP_MAX_EXPORT_BATCH_SIZE=200

The number of payloads that are rejected for being oversize can be found under Settings > Span usage > Unmanaged.