Warning
The otel4s-experimental
project provides no binary compatibility guarantees between releases.
Changes made in this repository may be completely incompatible with previous versions.
otel4s-experimental
is a companion project for the otel4s. The key points of the repository:
- Develop and test new experimental features
- Provide access to the unstable functionality without breaking the
otel4s
- Some features may be upstreamed to the
otel4s
eventually
Add the otel4s-experimental-metrics
dependency to the build.sbt
:
libraryDependencies ++= Seq(
"org.typelevel" %% "otel4s-experimental-metrics" % "0.5.0"
)
Important
IOMetrics
instrumentation is available only on JVM platform.
Example:
import cats.effect.{IO, IOApp}
import org.typelevel.otel4s.experimental.metrics._
import org.typelevel.otel4s.oteljava.OtelJava
object Main extends IOApp.Simple {
def app: IO[Unit] = ???
def run: IO[Unit] =
OtelJava.autoConfigured[IO]().use { otel4s =>
otel4s.meterProvider.get("service.meter").flatMap { implicit meter =>
IOMetrics.register[IO]().surround(app)
}
}
}
The metrics can be visualized in Grafana using this dashboard.
The provided metrics:
cats.effect.std.queue.size
- the current number of the elements in the queuecats.effect.std.queue.enqueued
- the total (lifetime) number of enqueued elementscats.effect.std.queue.offer.blocked
- the current number of the 'blocked' offererscats.effect.std.queue.take.blocked
- the current number of the 'blocked' takers
Example:
import cats.effect.{IO, IOApp}
import cats.effect.std.Queue
import org.typelevel.otel4s.{Attribute, Attributes}
import org.typelevel.otel4s.experimental.metrics._
import org.typelevel.otel4s.oteljava.OtelJava
object Main extends IOApp.Simple {
def run: IO[Unit] =
OtelJava.autoConfigured[IO]().use { otel4s =>
otel4s.meterProvider.get("service.meter").flatMap { implicit meter =>
val attributes = Attributes(Attribute("queue.name", "auth events"))
for {
queue <- InstrumentedQueue.unbounded[IO, String](attributes = attributes)
// use the instrumented queue
} yield ()
}
}
}
The provided metrics:
- Class
jvm.class.count
jvm.class.loaded
jvm.class.unloaded
- CPU
jvm.cpu.count
jvm.cpu.recent_utilization
jvm.cpu.time
- GC
jvm.gc.duration
- Memory
jvm.memory.committed
jvm.memory.limit
jvm.memory.used
jvm.memory.used_after_last_gc
- Thread
jvm.thread.count
Example:
import cats.effect.{IO, IOApp}
import org.typelevel.otel4s.experimental.metrics._
import org.typelevel.otel4s.sdk._
object Main extends IOApp.Simple {
def app: IO[Unit] = ???
def run: IO[Unit] =
OpenTelemetrySdk.autoConfigured[IO]().use { autoConfigured =>
val sdk = autoConfigured.sdk
sdk.meterProvider.get("service.meter").flatMap { implicit meter =>
RuntimeMetrics.register[IO].surround(app)
}
}
}
Add the otel4s-experimental-trace
dependency to the build.sbt
:
libraryDependencies ++= Seq(
"org.typelevel" %%% "otel4s-experimental-trace" % "0.5.0"
)
The body of a method annotated with @span
will be wrapped into a span:
import cats.effect.IO
import org.typelevel.otel4s.trace.Tracer
import org.typelevel.otel4s.experimental.trace.{attribute, span}
case class User(name: String)
class Service[F[_]: Tracer] {
@span
def findUser(
@attribute userId: Long,
@attribute("user.hash") hash: String
): F[User] = ???
}
expands into:
class Service[F[_]: Tracer] {
def findUser(
userId: Long,
hash: String
): F[User] =
Tracer[F].span(
"findUser",
Attribute("userId", userId), Attribute("user.hash", hash)
).surround(???)
}
The macro works with variables too:
implicit val tracer: Tracer[IO] = ???
@span("custom_name")
val strictUser: IO[User] = ???
expands into:
val strictUser: IO[User] =
Tracer[IO].span("custom_name").surround(???)