All Downloads are FREE. Search and download functionalities are using the official Maven repository.

zio.telemetry.opentelemetry.OpenTelemetry.scala Maven / Gradle / Ivy

There is a newer version: 3.0.0-RC26
Show newest version
package zio.telemetry.opentelemetry

import io.opentelemetry.api
import zio._
import zio.metrics.{MetricClient, MetricListener}
import zio.telemetry.opentelemetry.baggage.Baggage
import zio.telemetry.opentelemetry.context.ContextStorage
import zio.telemetry.opentelemetry.logging.Logging
import zio.telemetry.opentelemetry.metrics.Meter
import zio.telemetry.opentelemetry.metrics.internal.{Instrument, InstrumentRegistry, OtelMetricListener}
import zio.telemetry.opentelemetry.tracing.Tracing

/**
 * The entrypoint to telemetry functionality for tracing, metrics, logging and baggage.
 */
object OpenTelemetry {

  /**
   * A global singleton for the entrypoint to telemetry functionality for tracing, metrics, logging and baggage. Should
   * be used with SDK
   * Autoconfiguration module and/or Automatic instrumentation Java agent.
   *
   * @see
   *   Usage
   *   with OpenTelemetry automatic instrumentation
   */
  val global: TaskLayer[api.OpenTelemetry] =
    ZLayer(ZIO.attempt(api.GlobalOpenTelemetry.get()))

  /**
   * Use when you need to configure an instance of OpenTelemetry programmatically.
   *
   * Example:
   * [[https://github.com/zio/zio-telemetry/blob/series/2.x/opentelemetry-example/src/main/scala/zio/telemetry/opentelemetry/example/otel/OtelSdk.scala]]
   *
   * @param zio
   *   scoped ZIO value that returns a configured instance of [[io.opentelemetry.api.OpenTelemetry]], thus ensuring that
   *   the returned instance will be closed.
   */
  def custom(zio: => ZIO[Scope, Throwable, api.OpenTelemetry]): TaskLayer[api.OpenTelemetry] =
    ZLayer.scoped(zio)

  val noop: ULayer[api.OpenTelemetry] =
    ZLayer.succeed(api.OpenTelemetry.noop())

  /**
   * Use when you need to instrument spans manually.
   *
   * @param instrumentationScopeName
   *   name uniquely identifying the instrumentation scope, such as the instrumentation library, package, or fully
   *   qualified class name
   * @param instrumentationVersion
   *   version of the instrumentation scope (e.g., "1.0.0")
   * @param schemaUrl
   *   schema URL
   */
  def tracing(
    instrumentationScopeName: String,
    instrumentationVersion: Option[String] = None,
    schemaUrl: Option[String] = None,
    logAnnotated: Boolean = false
  ): URLayer[api.OpenTelemetry with ContextStorage, Tracing] = {
    val tracerLayer = ZLayer(
      ZIO.serviceWith[api.OpenTelemetry] { openTelemetry =>
        val builder = openTelemetry.tracerBuilder(instrumentationScopeName)

        instrumentationVersion.foreach(builder.setInstrumentationVersion)
        schemaUrl.foreach(builder.setSchemaUrl)

        builder.build
      }
    )

    tracerLayer >>> Tracing.live(logAnnotated)
  }

  /**
   * Use when you need to instrument metrics manually.
   *
   * @param instrumentationScopeName
   *   name uniquely identifying the instrumentation scope, such as the instrumentation library, package, or fully
   *   qualified class name
   * @param instrumentationVersion
   *   version of the instrumentation scope (e.g., "1.0.0")
   * @param schemaUrl
   *   schema URL
   */
  def metrics(
    instrumentationScopeName: String,
    instrumentationVersion: Option[String] = None,
    schemaUrl: Option[String] = None,
    logAnnotated: Boolean = false
  ): URLayer[api.OpenTelemetry with ContextStorage, Meter with Instrument.Builder] = {
    val meterLayer   = ZLayer(
      ZIO.serviceWith[api.OpenTelemetry] { openTelemetry =>
        val builder = openTelemetry.meterBuilder(instrumentationScopeName)

        instrumentationVersion.foreach(builder.setInstrumentationVersion)
        schemaUrl.foreach(builder.setSchemaUrl)

        builder.build()
      }
    )
    val builderLayer = meterLayer >>> Instrument.Builder.live(logAnnotated)

    builderLayer >+> (builderLayer >>> Meter.live)
  }

  /**
   * Use when you want to allow a seamless integration with ZIO runtime and JVM metrics.
   *
   * By default this layer enables the propagation of ZIO runtime metrics only. For JVM metrics you need to provide
   * `DefaultJvmMetrics.live.unit`.
   */
  def zioMetrics: URLayer[Instrument.Builder, Unit] = {
    val metricListenerLifecycleLayer = ZLayer.scoped {
      ZIO.serviceWithZIO[MetricListener] { metricListener =>
        Unsafe.unsafe { implicit unsafe =>
          ZIO.acquireRelease(
            ZIO.succeed(MetricClient.addListener(metricListener))
          )(_ => ZIO.succeed(MetricClient.removeListener(metricListener)))
        }
      }
    }

    Runtime.enableRuntimeMetrics >>>
      InstrumentRegistry.concurrent >>>
      OtelMetricListener.zioMetrics >>>
      metricListenerLifecycleLayer
  }

  /**
   * Use when you need to propagate calls to `ZIO.log*` as OTEL Log signals.
   *
   * @param instrumentationScopeName
   *   name uniquely identifying the instrumentation scope, such as the instrumentation library, package, or fully
   *   qualified class name
   * @param logLevel
   *   configures the logger to propagate the log records only when the log level is more than specified
   */
  def logging(
    instrumentationScopeName: String,
    logLevel: LogLevel = LogLevel.Info
  ): URLayer[api.OpenTelemetry with ContextStorage, Unit] = {
    val loggerProviderLayer = ZLayer(ZIO.serviceWith[api.OpenTelemetry](_.getLogsBridge))

    loggerProviderLayer >>> Logging.live(instrumentationScopeName, logLevel)
  }

  /**
   * Use when you need to pass contextual information between spans.
   *
   * @param logAnnotated
   *   propagate ZIO log annotations as Baggage key/values if it is set to true
   */
  def baggage(logAnnotated: Boolean = false): URLayer[ContextStorage, Baggage] =
    Baggage.live(logAnnotated)

  /**
   * Use when you do not use automatic instrumentation.
   */
  def contextZIO: ULayer[ContextStorage] =
    ContextStorage.fiberRef

  /**
   * Use when you use automatic instrumentation.
   */
  def contextJVM: ULayer[ContextStorage] =
    ContextStorage.native

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy