ocaml-opentelemetry/src/lib/meter_provider.ml
2026-03-03 15:14:32 -05:00

78 lines
2.6 KiB
OCaml

open Opentelemetry_emitter
open struct
let provider_ : Meter.t Atomic.t = Atomic.make Meter.dummy
end
let get () : Meter.t = Atomic.get provider_
let set (t : Meter.t) : unit = Atomic.set provider_ t
let clear () : unit = Atomic.set provider_ Meter.dummy
(** Get a meter pre-configured with a fixed set of attributes added to every
metric it emits, forwarding to the current global meter. Intended to be
called once at the top of a library module.
@param name instrumentation scope name (recorded as [otel.scope.name])
@param version
instrumentation scope version (recorded as [otel.scope.version])
@param __MODULE__
the OCaml module name, typically the [__MODULE__] literal (recorded as
[code.namespace])
@param attrs additional fixed attributes *)
let get_meter ?name ?version ?(attrs : (string * [< Value.t ]) list = [])
?__MODULE__ () : Meter.t =
let extra =
Scope_attributes.make_attrs ?name ?version ~attrs ?__MODULE__ ()
in
{
Meter.emit =
Emitter.make ~signal_name:"metrics"
~enabled:(fun () -> Emitter.enabled (Atomic.get provider_).emit)
~emit:(fun metrics ->
(match extra with
| [] -> ()
| _ -> List.iter (fun m -> Metrics.add_attrs m extra) metrics);
Emitter.emit (Atomic.get provider_).emit metrics)
();
clock = { Clock.now = (fun () -> Clock.now (Clock.Main.get ())) };
}
(** Emit with current meter *)
let[@inline] emit (m : Metrics.t) : unit = Emitter.emit (get ()).emit [ m ]
(** A Meter.t that lazily reads the global at emit time *)
let default_meter : Meter.t = get_meter ()
let minimum_min_interval_ = Mtime.Span.(100 * ms)
let default_min_interval_ = Mtime.Span.(4 * s)
let clamp_interval_ interval =
if Mtime.Span.is_shorter interval ~than:minimum_min_interval_ then
minimum_min_interval_
else
interval
let add_to_exporter ?(min_interval = default_min_interval_) (_exp : Exporter.t)
(self : Meter.t) : unit =
let limiter =
Interval_limiter.create ~min_interval:(clamp_interval_ min_interval) ()
in
Globals.add_on_tick_callback (fun () ->
if Interval_limiter.make_attempt limiter then (
let metrics = Meter.collect self in
if metrics <> [] then Emitter.emit self.emit metrics
))
let add_to_main_exporter ?(min_interval = default_min_interval_)
(self : Meter.t) : unit =
let limiter =
Interval_limiter.create ~min_interval:(clamp_interval_ min_interval) ()
in
Globals.add_on_tick_callback (fun () ->
if Interval_limiter.make_attempt limiter then (
let metrics = Meter.collect self in
if metrics <> [] then Emitter.emit self.emit metrics
))