Java
Traces | Metrics | App Logs | Custom Logs | Profiling |
---|---|---|---|---|
✅ | ✅ | ✅ | ✅ | ✅ |
This guide walks you through setting up Application Performance Monitoring (APM) on a Java application. These instructions can also be found on the Installation page in your Middleware Account. View example code here.
Prerequisites
1 Java Version
Java version 8
or above. Check your Java version with the following command:
Shell
java --version
Install
Step 1: Download JAR File
Download the latest Middleware instrumentation JAR file from the Github Release Page.
Step 2: Container Variables
Applications running in a container require an additional environment variable. If your application is not running in a container, move to Step 3.
Docker
Add the following environment variable to your application:
Shell
MW_AGENT_SERVICE=<DOCKER_BRIDGE_GATEWAY_ADDRESS>
The DOCKER_BRIDGE_GATEWAY_ADDRESS
is the IP address of the gateway between the Docker host and bridge network. This is 172.17.0.1
by default. Learn more about Docker bridge networking here
Kubernetes
Run the following command to find the mw-service
in Kubernetes:
Shell
kubectl get service --all-namespaces | grep mw-service
Add the following environment variable to your application deployment YAML file:
Shell
MW_AGENT_SERVICE=mw-service.mw-agent-ns.svc.cluster.local
Step 3: Capture Application Data
Traces
Distributed tracing will be automatically enabled upon completing Step 4: Run Application.
Metrics
Metrics collection will be automatically enabled upon completing Step 4: Run Application.
Application & Custom Logs
Application Logs will be automatically enabled upon completing Step 4: Run Application.
To add custom logs, add this dependency in the pom.xml
file:
main.java
<dependency> <groupId>io.github.middleware-labs</groupId> <artifactId>agent-apm-java</artifactId> <version>0.0.16</version> </dependency>
Run the following command to download the above dependencies:
Shell
mvn install
Import the logger package:
main.java
import io.github.middlewarelabs.agentapmjava.Logger;
Then utilize the following functions based on desired log severity levels.
main.java
Logger.info("info message"); Logger.debug("debug message"); Logger.warn("warn message"); Logger.error("error message");
Profiling
Application Profiling is automatically enabled upon completing Step 4: Run Application.
Stack Traces
Use the Logger.recordError(e)
method to record a stack trace when an error occurs. See an example of this method below.
main.java
import io.github.middlewarelabs.agentapmjava.Logger; try { int[] myNumbers = {1, 2, 3}; System.out.println(myNumbers[10]); } catch (Throwable e) { Logger.recordError(e); System.out.println("Something went wrong."); }
Step 4: Run Application
Run your application with the command given below.
# Run Java application with Middleware APM agent: # - Sets API key for authentication # - Specifies path to Middleware Java agent # - Configures service name and project name for APM # - Executes the Java application JAR file MW_API_KEY="<MW_API_KEY>" java -javaagent:/PATH/TO/middleware-javaagent-{version}.jar \ -Dotel.service.name={APM-SERVICE-NAME} \ -Dotel.resource.attributes=project.name={APM-PROJECT-NAME} \ -jar <YOUR_APP>.jar
# Sets API key, target URL, and service name # Attaches agent, specifies project name # Runs the application JAR file MW_API_KEY="<MW_API_KEY>"\ MW_TARGET=https://{YOUR_MW_TENET_ID}.middleware.io:4317 \ MW_SERVICE_NAME=<YOUR_SERVICE_NAME> \ java -javaagent:./middleware-javaagent.jar \ -Dotel.resource.attributes=project.name=<YOUR_PROJECT_NAME> \ -jar target/demo-0.0.1-SNAPSHOT.jar
Continuous Profiling
Continuous profiling captures real-time performance insights from your application to enable rapid identification of resource allocation, bottlenecks, and more. Navigate to the Continuous Profiling section to learn more about using Continuous Profiling with the Java APM.
To control continuous profiling, use the MW_APM_COLLECT_PROFILING environment variable:
Enable profiling
# Enable continuous profiling for Java app # Collects real-time performance data for # resource allocation and bottleneck analysis MW_API_KEY="<MW_API_KEY>" \ MW_APM_COLLECT_PROFILING=true \ java -javaagent:/PATH/TO/middleware-javaagent-{version}.jar \ -Dotel.service.name={APM-SERVICE-NAME} \ -Dotel.resource.attributes=project.name={APM-PROJECT-NAME} \ -jar <YOUR_APP>.jar
Disable profiling
# Disable continuous profiling for Java app MW_API_KEY="<MW_API_KEY>" \ MW_APM_COLLECT_PROFILING=false java -javaagent:/PATH/TO/middleware-javaagent-{version}.jar \ -Dotel.service.name={APM-SERVICE-NAME} \ -Dotel.resource.attributes=project.name={APM-PROJECT-NAME} \ -jar <YOUR_APP>.jar
If the variable is not set, continuous profiling is enabled by default.
Head Sampling
Head sampling is a technique that makes sampling decisions at the earliest possible stage. It determines whether to sample or drop a span or trace without inspecting the entire trace.
By default, Java APM samples all the spans and sends them to Middleware backend. If you wish to restrict the amount of spans you send to Middleware, you can introduce a trace sampler and adjust the sampling rate.
Available Samplers
- always_on: Samples every span, ensuring that 100% of traces are captured. Useful in development environments or when comprehensive trace data is needed.
- always_off: Does not sample any spans, effectively disabling tracing. Useful in production environments where tracing overhead needs to be minimized.
- traceidratio: Samples a fixed percentage of traces, determined by the
otel.traces.sampler.arg
environment variable. For example, settingotel.traces.sampler.arg
to0.1
will sample 10% of traces. - parentbased_always_on: If the parent span is sampled, the child span will also be sampled. If there is no parent, the span will be sampled.
- parentbased_always_off: If the parent span is not sampled, the child span will also not be sampled. If there is no parent, the span will not be sampled.
- parentbased_traceidratio: Uses the
traceidratio
sampler for root spans, with the sampling rate set byotel.traces.sampler.arg
.
Environment Variables
You can set OTEL_TRACES_SAMPLER
environment variable to select the sampler and OTEL_TRACES_SAMPLER_ARG
to set the sampling rate.
For example, to configure the SDK to sample parent spans such that only 10% of traces get created:
export OTEL_TRACES_SAMPLER="parentbased_traceidratio" export OTEL_TRACES_SAMPLER_ARG="0.1
Java System Properties
You can set otel.traces.sampler
Java system property to select the sampler and otel.traces.sampler.arg
to set the sampling rate.
Direct Arguments
otel.traces.sampler
and ``otel.traces.sampler.argproperties can also be passed directly to the
java` executable as shown below.
# Configure trace sampling for Java app: # Uses parentbased_traceidratio sampler # Sets sampling rate to 10% of traces # Balances data collection and performance MW_API_KEY="<MW_API_KEY>" java -javaagent:/PATH/TO/middleware-javaagent-{version}.jar \ -Dotel.service.name={APM-SERVICE-NAME} \ -Dotel.resource.attributes=project.name={APM-PROJECT-NAME} \ -Dotel.traces.sampler=otel.traces.sampler=parentbased_traceidratio \ -Dotel.traces.sampler.arg=0.1 \ -jar <YOUR_APP>.jar
This will use parentbased_traceidratio
to sample 10% of your root spans.
Properties file
These properties can be set in a Java system properties file and based to the java
executable as shown below
MW_API_KEY="<MW_API_KEY>" java -javaagent:/PATH/TO/middleware-javaagent-{version}.jar \ -Dotel.service.name={APM-SERVICE-NAME} \ -Dotel.resource.attributes=project.name={APM-PROJECT-NAME} \ -Dotel.javaagent.configuration-file={PATH-TO-PROPERTY-FILE} \ -jar <YOUR_APP>.jar
You can also set location of the Java system properties file in an environment variable and skip passing it as an argument to the java
command.
OTEL_JAVAAGENT_CONFIGURATION_FILE={PATH-TO-PROPERTY-FILE}
Replace {PATH-TO-PROPERTY-FILE}
above to the location where your Java system properties file is located.
Example Java system properties file should look like below
# Middleware Trace Sampling otel.traces.sampler=parentbased_traceidratio otel.traces.sampler.arg=0.1
This sample Java system properties will use parentbased_traceidratio
to sample 10% of your root spans.
Logging and debug mode
This document outlines the environment variables and options used to configure debug mode for OpenTelemetry Java Instrumentation.
Environment Variables
Exporter Configuration
OTEL_TRACES_EXPORTER=logging
- Configures the tracer to log trace data to the console.
- Useful for viewing trace data directly in your application logs.
OTEL_METRICS_EXPORTER=logging
- Sets the metrics exporter to log metrics data to the console.
- Allows for immediate visibility of metrics in your application logs.
OTEL_LOGS_EXPORTER=logging
- Configures the logs exporter to output log data to the console.
- Enables viewing of OpenTelemetry log data alongside your application logs.
Logging Configuration
OTEL_EXPORTER_LOGGING_PREFIX="OTEL DEBUG: "
- Adds a prefix to all OpenTelemetry logged data.
- Helps distinguish OpenTelemetry logs from other application logs.
Sampling Configuration
OTEL_TRACES_SAMPLER=always_on
- Ensures that all traces are captured and logged.
- Useful for debugging but can generate a large volume of data.
Debug mode:
OTEL_JAVAAGENT_DEBUG=true
- Enables debug logging for the OpenTelemetry Java agent.
- Provides detailed information about the agent's operations.
Usage
To use these settings, you can set the environment variables before running your Java application with the OpenTelemetry agent. Here's an example command:
MW_API_KEY="<MW_API_KEY>" \ OTEL_TRACES_EXPORTER=logging \ OTEL_METRICS_EXPORTER=logging \ OTEL_LOGS_EXPORTER=logging \ OTEL_EXPORTER_LOGGING_PREFIX="OTEL DEBUG: " \ OTEL_TRACES_SAMPLER=always_on \ OTEL_JAVAAGENT_DEBUG=true java -javaagent:/PATH/TO/middleware-javaagent-{version}.jar \ -Dotel.service.name={APM-SERVICE-NAME} \ -Dotel.resource.attributes=project.name={APM-PROJECT-NAME} \
Replace path/to/middleware-javaagent-{version}.jar
with the actual path to your Middleware Java agent JAR file, and your-application.jar
with the path to your application's JAR file.
This table shows the available configuration settings other than the env variables mentioned above.
Environment Variable | Default Value | Description |
---|---|---|
MW_PROFILING_SERVER_URL | null | URL for the profiling server |
MW_PROFILING_ALLOC | "512k" | Allocation size for profiling |
MW_PROFILING_LOCK | "10ms" | Lock duration for profiling |
MW_AGENT_SERVICE | "localhost" | Agent service address |
MW_SERVICE_NAME | "" | Name of the service |
MW_AUTH_URL | "https://app.middleware.io/api/v1/auth" | Authentication URL |
MW_APM_COLLECT_PROFILING | "true" | Enable/disable profiling collection |
MW_APM_COLLECT_TRACES | "true" | Enable/disable trace collection |
MW_APM_COLLECT_LOGS | "true" | Enable/disable log collection |
MW_APM_COLLECT_METRICS | "true" | Enable/disable metric collection |
MW_DISABLE_TELEMETRY | "true" | Enable/disable telemetry |
MW_TARGET | "" | Target endpoint for data sending |
MW_API_KEY | null | API key for authentication |
MW_PROPAGATORS | "b3" | Context propagators to use |
MW_CUSTOM_RESOURCE_ATTRIBUTE | null | Custom resource attributes |
MW_LOG_LEVEL | null | Log level for the application |
MW_ENABLE_GZIP | "true" | Enable/disable GZIP compression |
MW_AGENT | "true" | Enable/disable the agent |
Need assistance or want to learn more about Middleware? Contact our support team in Slack.