In this example, we’ll use Honeycomb to collect and visualize metrics and traces produced by an otel4s application. Unlike the Jaeger example, you don’t need to set up a collector service locally—telemetry is sent directly to the Honeycomb API.
Honeycomb offers up to 20 million spans per month for free accounts. It provides robust analysis and visualization tools that are excellent for exploring telemetry data.
Project Setup
Configure your project with the required dependencies:
// Add to build.sbt
libraryDependencies ++= Seq(
"org.typelevel" %% "otel4s-oteljava" % "0.15.0",
"io.opentelemetry" % "opentelemetry-exporter-otlp" % "1.59.0" % Runtime,
"io.opentelemetry" % "opentelemetry-sdk-extension-autoconfigure" % "1.59.0" % Runtime
)
run / fork := true
javaOptions += "-Dotel.java.global-autoconfigure.enabled=true"
javaOptions += "-Dotel.service.name=honeycomb-example"
javaOptions += "-Dotel.exporter.otlp.endpoint=https://api.honeycomb.io/"
OpenTelemetry SDK Configuration
The OpenTelemetry SDK can be configured via system properties or environment variables. See the full list of environment variable configurations for more options.
Acquiring a Honeycomb API Key
Log into your account and go to the environment settings page.
Find your generated API key in the environment settings.
Use Different Environments
Create separate environments for test, production, and local development. Each will have its own API Key to organize your data in Honeycomb.
For more details, see the Honeycomb API Keys documentation.
Honeycomb Configuration
Configure the API key and dataset name using environment variables:
export OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=your-api-key,x-honeycomb-dataset=otel-metrics"
Headers:
x-honeycomb-team - Your Honeycomb API key
x-honeycomb-dataset - The dataset name for metrics (defaults to unknown_metrics if not set)
Each service’s traces will automatically land in a dataset named after the otel.service.name configuration.
For more information, see the Honeycomb OpenTelemetry documentation.
Application Example
This example demonstrates both metrics and tracing:
import java.util.concurrent.TimeUnit
import cats.effect.{Async, IO, IOApp}
import cats.effect.std.Console
import cats.effect.std.Random
import cats.syntax.all._
import org.typelevel.otel4s.{Attribute, AttributeKey}
import org.typelevel.otel4s.oteljava.OtelJava
import org.typelevel.otel4s.metrics.Histogram
import org.typelevel.otel4s.trace.Tracer
import scala.concurrent.duration._
trait Work[F[_]] {
def doWork: F[Unit]
}
object Work {
def apply[F[_]: Async: Tracer: Console](histogram: Histogram[F, Double]): Work[F] =
new Work[F] {
def doWork: F[Unit] =
Tracer[F].span("Work.DoWork").use { span =>
span.addEvent("Starting the work.") *>
doWorkInternal(steps = 10) *>
span.addEvent("Finished working.")
}
def doWorkInternal(steps: Int): F[Unit] = {
val step = Tracer[F]
.span("internal", Attribute(AttributeKey.long("steps"), steps.toLong))
.surround {
for {
random <- Random.scalaUtilRandom
delay <- random.nextIntBounded(1000)
_ <- Async[F].sleep(delay.millis)
_ <- Console[F].println("Doin' work")
} yield ()
}
val metered = histogram.recordDuration(TimeUnit.MILLISECONDS).surround(step)
if (steps > 0) metered *> doWorkInternal(steps - 1) else metered
}
}
}
object TracingExample extends IOApp.Simple {
def run: IO[Unit] = {
OtelJava
.autoConfigured[IO]()
.evalMap { otel4s =>
otel4s.tracerProvider.get("com.service.runtime")
.flatMap { implicit tracer: Tracer[IO] =>
for {
meter <- otel4s.meterProvider.get("com.service.runtime")
histogram <- meter.histogram[Double]("work.execution.duration").create
_ <- Work[IO](histogram).doWork
} yield ()
}
}
.use_
}
}
Running the Application
export OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=your-api-key,x-honeycomb-dataset=honeycomb-example"
sbt run
Viewing Data in Honeycomb
Navigate to https://ui.honeycomb.io/ to query and visualize your collected traces and metrics.
Traces
You’ll see the trace hierarchy with:
- Parent span “Work.DoWork”
- Nested “internal” spans
- Events marking work start and completion
- Attributes including the “steps” counter
Metrics
The work.execution.duration histogram will show:
- Execution time distribution
- Statistical aggregations (p50, p95, p99)
- Time-series visualization
Use Honeycomb’s query builder to create custom views, breakdowns, and alerts based on your telemetry data.