Scala
| Traces | Metrics | App Logs | Custom Logs | Profiling |
|---|---|---|---|---|
| ✅ | ✅ | ✅ | ✅ | ✅ |
1. Prerequisites#
- Middleware Host Agent running on the same machine (or reachable). In containers, point apps to the agent with MW_AGENT_SERVICE: Docker 172.17.0.1, Kubernetes mw-service.mw-agent-ns.svc.cluster.local.
- Scala/SBT project (Scala 2.11.6+ is fine) and JDK 8+. Check using:
scala --version java --version
1 Download the Middleware Java agent JAR#
Grab the latest release of the Middleware Java agent JAR from GitHub and place it in your project (e.g., project root or a lib/ directory).
Keep the filename versioned (e.g., middleware-javaagent-1.x.y.jar) and commit it or fetch it during CI.
2 Wire the agent in build.sbt#
Enable a forked JVM and pass -javaagent + service name via javaOptions. (Forking is required for SBT to apply javaOptions to your app’s run.)
// build.sbt
ThisBuild / scalaVersion := "2.13.14"
// ensure SBT forks for run so javaOptions apply
(run / fork) := true
(run / javaOptions) ++= Seq(
// point to where you stored the agent jar
"-javaagent:middleware-javaagent-1.6.0.jar",
// logical service name shown in Middleware APM
"-Dotel.service.name={APM-SERVICE-NAME}"
)(Your existing Scala page uses the same javaOptions structure; we’re just adding the fork so it takes effect.) Alternative: if you prefer, you can manage javaagents via the community sbt-javaagent plugin instead of manual javaOptions.
3 Run your app with your account key#
Your Middleware API key is required; export it and run the app via SBT:
MW_API_KEY="<API-key>" sbt runIf you’re not running a Host Agent, point the agent straight to Middleware’s ingest and keep the rest identical:
// build.sbt (add one more property)
(run / javaOptions) ++= Seq(
"-Dotel.exporter.otlp.endpoint=https://ruplp.middleware.io" // serverless ingest URL
)OpenTelemetry Java agents accept the standard otel.exporter.otlp.endpoint property; the SDK constructs the signal-specific paths as needed for OTLP/HTTP. You’ll still export MW_API_KEY=... alongside sbt run.
(Optional) Custom logs from your Scala code#
If you want to emit custom logs (INFO/WARN/DEBUG/ERROR) that correlate with traces, add the agent-apm-java library to your build and use its Logger:
- Add dependency (SBT):
// build.sbt libraryDependencies += "io.github.middleware-labs" % "agent-apm-java" % "0.0.18" - Use the logger (Scala/Java interop):
// anywhere in your app code import io.github.middlewarelabs.agentapmjava.Logger Logger.info("info message") Logger.debug("debug message") Logger.warn("warn message") Logger.error("error message") - Record stack errors Call
recordErrorfrom a catch block to attach stack traces to the active span:try { // ... } catch { case e: Exception => io.github.middlewarelabs.agentapmjava.Logger.recordError(e) throw e }
View your data#
After you start the app, wait 3–5 minutes, then open Traces, Logs, and Profiling in Middleware to verify data is flowing. (This mirrors your Scala page’s flow.)
SBT notes & tips#
- Forking is required for
javaOptions(like-javaagent) to apply tosbt run. Configure(run / fork) := true. - If you package with sbt-native-packager, you can also push Java options into start scripts via
Universal / javaOptionsor add extra defines to scripts. - When sending data without a local collector,
otel.exporter.otlp.endpointis the standard knob; OTLP exporters also support header-based auth viaotel.exporter.otlp.headersif you ever need it.
Environment variables#
| Key/Option | Where it's used | Purpose | Example |
|---|---|---|---|
MW_AGENT_SERVICE | Containerized host-based | Route app → Host Agent | 172.17.0.1 (Docker), mw-service.mw-agent-ns.svc.cluster.local (K8s). |
MW_API_KEY | Runtime env | Your Middleware account key, required for export | export MW_API_KEY="…"; then sbt run. |
-Dotel.service.name | javaOptions | Logical service name shown in APM | -Dotel.service.name=payments-scala |
-Dotel.exporter.otlp.endpoint | javaOptions(serverless) | Send telemetry directly to Middleware ingest (no Host Agent) | -Dotel.exporter.otlp.endpoint=https://ruplp.middleware.io. |
Troubleshooting#
- No telemetry appears → Confirm
(run / fork) := trueand the-javaagent:path is correct. SBT only applies javaOptions to a forked run. - Still no data on serverless → Ensure the endpoint property is set (
otel.exporter.otlp.endpoint) and that your key is present. OTLP HTTP exporters derive/v1/{signal}paths automatically when you set a base endpoint. - Packaging instead of
sbt run→ Use sbt-native-packager’sUniversal / javaOptionsor script defines so the agent flags end up in the generated start scripts.
Need assistance or want to learn more about Middleware? Contact our support team at [email protected] or join our Slack channel.