ScalaTest extension that instruments your tests with OpenTelemetry.
This example demonstrates how to send trace data to Jaeger in localhost.
Before you start, you need to run Jaeger in a Docker container.
services:
jeager:
image: jaegertracing/all-in-one:latest
ports:
- "4317:4317"
- "16686:16686"
docker compose up -d
Add the following configuration to your build.sbt
.
lazy val `my-project` = (project in file("my-project"))
.settings(
// Add dependencies
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "3.2.18" % Test,
"io.opentelemetry" % "opentelemetry-sdk" % "1.38.0" % Test,
"io.opentelemetry" % "opentelemetry-exporter-otlp" % "1.38.0" % Test,
"io.opentelemetry.semconv" % "opentelemetry-semconv" % "1.21.0-alpha" % Test,
"dev.nomadblacky" %% "scalatest-otel-reporter" % "<version>" % Test,
),
// Add the reporter class
Test / testOptions += Tests.Argument(
TestFrameworks.ScalaTest,
"-C",
"example.JaegerTestReporter",
),
)
Create a reporter class that extends OpenTelemetryTestReporter
and implements the otel
method.
Below is an example of sending trace data to Jaeger in localhost.
package example
import dev.nomadblacky.scalatest_otel_reporter.OpenTelemetrySdkTestReporter
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.common.Attributes
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter
import io.opentelemetry.sdk.OpenTelemetrySdk
import io.opentelemetry.sdk.resources.Resource
import io.opentelemetry.sdk.trace.SdkTracerProvider
import io.opentelemetry.sdk.trace.`export`.BatchSpanProcessor
import io.opentelemetry.semconv.ResourceAttributes
import java.util.concurrent.TimeUnit
// Mix-In OpenTelemetryTestReporter
class JaegerTestReporter extends OpenTelemetrySdkTestReporter {
def initOpenTelemetry: OpenTelemetrySdk = {
// Direct trace data to Jaeger on localhost
val jaegerOtlpExporter =
OtlpGrpcSpanExporter.builder.setEndpoint("http://localhost:4317").setTimeout(30, TimeUnit.SECONDS).build
// Configure the service name (recommended)
val serviceNameResource =
Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, "scalatest-otel-demo-manual"))
// Configure the SpanProcessor
val tracerProvider = SdkTracerProvider.builder
.addSpanProcessor(BatchSpanProcessor.builder(jaegerOtlpExporter).build)
.setResource(Resource.getDefault.merge(serviceNameResource))
.build
// Return OpenTelemetry instance
OpenTelemetrySdk.builder.setTracerProvider(tracerProvider).build
}
}
Implement the test as usual.
package example
import org.scalatest.funsuite.AnyFunSuiteLike
class SimpleTests extends AnyFunSuiteLike {
test("sum") {
assert(1 + 1 == 2)
}
test("sub") {
assert(1 - 1 == 0)
}
}
class FailedTests extends AnyFunSuiteLike {
test("failed assertion") {
assert(1 + 1 == 3)
}
test("throw an exception") {
throw new RuntimeException("An exception occurred")
}
}
// ...
Execute the test in the sbt shell.
sbt
> my-project/test
Open the Jaeger UI in your browser (http://localhost:16686/) and you will see the trace data.
You can configure the behavior of the reporter by ScalaTest's config map.
Test / testOptions += Tests.Argument(
TestFrameworks.ScalaTest,
"-C",
"example.JaegerTestReporter",
"-Dscalatest-otel-reporter.root-span-name=my-awesome-tests",
)
Key | Description | Default |
---|---|---|
scalatest-otel-reporter.root-span-name |
The name of the root span. | scalatest |