This guide walks you through instrumenting your Scala application with OpenTelemetry and sending traces to SigNoz. Scala runs on the JVM, so the OpenTelemetry Java agent works directly—no additional SDK or Scala-specific library required.
Prerequisites
- Java 8+
- Scala 2.x or 3.x
- SBT, Maven, or Gradle
- An instance of SigNoz (either Cloud or Self-Hosted)
Auto-instrumented frameworks
The OpenTelemetry Java agent instruments these Scala frameworks automatically—no code changes required:
| Framework | Min version | What's instrumented |
|---|---|---|
| Play MVC | 2.4 | HTTP routes, controller spans |
| Play WS | 1.0 | HTTP client spans and metrics |
| Akka HTTP | 10.0 | Server spans, client spans, metrics, routes |
| Akka Actors | 2.3 | Context propagation |
| Apache Pekko | 1.0 | Context propagation, HTTP instrumentation |
| ZIO | 2.0 | Context propagation |
| ZIO HTTP | 3.0 | Route span naming |
| Scala ForkJoinPool | 2.8 | Context propagation |
See the full supported libraries list for all frameworks and versions.
Send traces to SigNoz
Step 1. Download the OpenTelemetry Java agent
wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
Step 2. Set environment variables
export OTEL_RESOURCE_ATTRIBUTES="service.name=<service-name>,service.version=<service-version>"
export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.signoz.cloud:443"
export OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=<your-ingestion-key>"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_METRICS_EXPORTER="none"
export OTEL_LOGS_EXPORTER="none"
Verify these values:
<region>: Your SigNoz Cloud region.<your-ingestion-key>: Your SigNoz ingestion key.<service-name>: A descriptive name for your service (e.g.,checkout-service).<service-version>(optional): Your release version, image tag, or git SHA (e.g.,1.4.2,a01dbef8).
Set service.version to a per-build value, not a static string. SigNoz detects a deployment each time this value changes. Common sources:
- Bash / shell:
service.version=$(git rev-parse --short HEAD) - GitHub Actions:
service.version=${{ github.sha }} - GitLab CI:
service.version=$CI_COMMIT_SHORT_SHA - Kubernetes: inject from your Helm chart image tag or CI variable
Step 3. Run your application
SBT (recommended)
SBT runs tasks in the same JVM process by default, so the agent can't attach. Enable forking in your build.sbt:
fork := true
run / javaOptions += "-javaagent:/path/to/opentelemetry-javaagent.jar"
Then run:
sbt run
Assembly or fat JAR
If you package your application with sbt-assembly or a similar plugin, attach the agent at startup:
java -javaagent:./opentelemetry-javaagent.jar -jar your-app-assembly.jar
Step 1. Add the agent to your Dockerfile
FROM eclipse-temurin:17-jre
WORKDIR /app
COPY target/scala-2.13/<my-app>-assembly.jar app.jar
RUN wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar -O opentelemetry-javaagent.jar
ENTRYPOINT ["java", "-javaagent:/app/opentelemetry-javaagent.jar", "-jar", "app.jar"]
Replace <my-app> with your assembled JAR name.
Step 2. Deploy to Kubernetes
Add these environment variables to your deployment manifest:
env:
- name: OTEL_RESOURCE_ATTRIBUTES
value: 'service.name=<service-name>,service.version=<service-version>'
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: 'https://ingest.<region>.signoz.cloud:443'
- name: OTEL_EXPORTER_OTLP_HEADERS
value: 'signoz-ingestion-key=<your-ingestion-key>'
- name: OTEL_EXPORTER_OTLP_PROTOCOL
value: 'http/protobuf'
- name: OTEL_METRICS_EXPORTER
value: 'none'
- name: OTEL_LOGS_EXPORTER
value: 'none'
Verify these values:
<region>: Your SigNoz Cloud region.<your-ingestion-key>: Your SigNoz ingestion key.<service-name>: A descriptive name for your service (e.g.,checkout-service).<service-version>(optional): Your release version, image tag, or git SHA (e.g.,1.4.2,a01dbef8).
Set service.version to a per-build value, not a static string. SigNoz detects a deployment each time this value changes. Common sources:
- Bash / shell:
service.version=$(git rev-parse --short HEAD) - GitHub Actions:
service.version=${{ github.sha }} - GitLab CI:
service.version=$CI_COMMIT_SHORT_SHA - Kubernetes: inject from your Helm chart image tag or CI variable
The OpenTelemetry Operator auto-injects the Java agent into your pods without modifying your container image.
Step 1. Set up the OpenTelemetry Operator
Install the Operator and Collector following the K8s OTel Operator installation guide.
Step 2. Create the Instrumentation resource
Create instrumentation.yaml to configure Java auto-instrumentation:
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: scala-instrumentation
spec:
exporter:
endpoint: http://otel-collector-collector:4318
propagators:
- tracecontext
- baggage
env:
- name: OTEL_EXPORTER_OTLP_PROTOCOL
value: "http/protobuf"
- name: OTEL_METRICS_EXPORTER
value: "none"
- name: OTEL_LOGS_EXPORTER
value: "none"
java:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:latest
Deploy this resource to your cluster.
Step 3. Add annotations to your deployment
Add these annotations to your pod template's metadata.annotations:
instrumentation.opentelemetry.io/inject-java: 'true'
resource.opentelemetry.io/service.name: '<service-name>'
resource.opentelemetry.io/service.version: '<service-version>'
Verify these values:
<service-name>: A descriptive name for your service (e.g.,checkout-service).<service-version>(optional): Your release version, image tag, or git SHA (e.g.,1.4.2,a01dbef8).
Set service.version to a per-build value, not a static string. SigNoz detects a deployment each time this value changes. Common sources:
- Bash / shell:
service.version=$(git rev-parse --short HEAD) - GitHub Actions:
service.version=${{ github.sha }} - GitLab CI:
service.version=$CI_COMMIT_SHORT_SHA - Kubernetes: inject from your Helm chart image tag or CI variable
Step 1. Add the agent to your Dockerfile
FROM eclipse-temurin:17-jre
WORKDIR /app
COPY target/scala-2.13/<my-app>-assembly.jar app.jar
RUN wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar -O opentelemetry-javaagent.jar
ENTRYPOINT ["java", "-javaagent:/app/opentelemetry-javaagent.jar", "-jar", "app.jar"]
Replace <my-app> with your assembled JAR name.
Step 2. Build and run
docker build -t my-scala-app .
docker run -p 8080:8080 \
-e OTEL_RESOURCE_ATTRIBUTES="service.name=<service-name>,service.version=<service-version>" \
-e OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.signoz.cloud:443" \
-e OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=<your-ingestion-key>" \
-e OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf" \
-e OTEL_METRICS_EXPORTER="none" \
-e OTEL_LOGS_EXPORTER="none" \
my-scala-app
Verify these values:
<region>: Your SigNoz Cloud region.<your-ingestion-key>: Your SigNoz ingestion key.<service-name>: A descriptive name for your service (e.g.,checkout-service).<service-version>(optional): Your release version, image tag, or git SHA (e.g.,1.4.2,a01dbef8).
Set service.version to a per-build value, not a static string. SigNoz detects a deployment each time this value changes. Common sources:
- Bash / shell:
service.version=$(git rev-parse --short HEAD) - GitHub Actions:
service.version=${{ github.sha }} - GitLab CI:
service.version=$CI_COMMIT_SHORT_SHA - Kubernetes: inject from your Helm chart image tag or CI variable
Step 1. Download the OpenTelemetry Java agent
Invoke-WebRequest -Uri "https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar" -OutFile "opentelemetry-javaagent.jar"
Step 2. Set environment variables
$env:OTEL_RESOURCE_ATTRIBUTES = "service.name=<service-name>,service.version=<service-version>"
$env:OTEL_EXPORTER_OTLP_ENDPOINT = "https://ingest.<region>.signoz.cloud:443"
$env:OTEL_EXPORTER_OTLP_HEADERS = "signoz-ingestion-key=<your-ingestion-key>"
$env:OTEL_EXPORTER_OTLP_PROTOCOL = "http/protobuf"
$env:OTEL_METRICS_EXPORTER = "none"
$env:OTEL_LOGS_EXPORTER = "none"
Verify these values:
<region>: Your SigNoz Cloud region.<your-ingestion-key>: Your SigNoz ingestion key.<service-name>: A descriptive name for your service (e.g.,checkout-service).<service-version>(optional): Your release version, image tag, or git SHA (e.g.,1.4.2,a01dbef8).
Set service.version to a per-build value, not a static string. SigNoz detects a deployment each time this value changes. Common sources:
- Bash / shell:
service.version=$(git rev-parse --short HEAD) - GitHub Actions:
service.version=${{ github.sha }} - GitLab CI:
service.version=$CI_COMMIT_SHORT_SHA - Kubernetes: inject from your Helm chart image tag or CI variable
Step 3. Run your application
SBT (recommended)
Add to your build.sbt:
fork := true
run / javaOptions += "-javaagent:C:\\path\\to\\opentelemetry-javaagent.jar"
Then run:
sbt run
Assembly or fat JAR
java -javaagent:.\opentelemetry-javaagent.jar -jar your-app-assembly.jar
Validate
With your application running, verify traces are flowing to SigNoz:
- Send a few requests to your application.
- In SigNoz, open the Services tab and click Refresh. Your service should appear.
- Go to the Traces tab to see your application's traces.
Troubleshooting
No traces in SigNoz after sbt run
The most common cause: SBT shares its JVM with your application by default, so the agent flag in javaOptions has no effect.
Fix: add fork := true to your build.sbt:
fork := true
run / javaOptions += "-javaagent:/path/to/opentelemetry-javaagent.jar"
Traces not showing up in SigNoz
Check environment variables:
echo $OTEL_EXPORTER_OTLP_ENDPOINT
echo $OTEL_RESOURCE_ATTRIBUTES
Enable debug logging:
OTEL_LOG_LEVEL=debug java -javaagent:./opentelemetry-javaagent.jar -jar app.jar
Look for span output in stdout. If spans appear locally but not in SigNoz, check your endpoint URL and ingestion key.
Test connectivity:
curl -v https://ingest.<region>.signoz.cloud:443/v1/traces
"Sharing is only supported for boot loader classes" warning
SBT prints this as [error] but it is harmless:
[error] OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
The Java agent modifies the bootstrap classpath, which disables JVM class-data sharing (CDS). It does not affect instrumentation or trace collection.
Agent not attaching
Make sure -javaagent comes before -jar:
# Correct
java -javaagent:./agent.jar -jar app.jar
# Wrong — agent flag after -jar is ignored
java -jar app.jar -javaagent:./agent.jar
Setup OpenTelemetry Collector (Optional)
The Collector sits between your app and SigNoz. Your app sends traces to the Collector, which then forwards them to SigNoz. Use it to filter noisy spans, redact sensitive data, or fan out to multiple backends.
See Switch from direct export to Collector for setup instructions.
Next steps
- Add manual instrumentation for custom spans and business context
- Set up alerts on your Scala service
Get Help
If you need help with the steps in this topic, please reach out to us on SigNoz Community Slack.
If you are a SigNoz Cloud user, please use in product chat support located at the bottom right corner of your SigNoz instance or contact us at cloud-support@signoz.io.