mirror of
https://github.com/ocaml-tracing/ocaml-opentelemetry.git
synced 2026-03-08 03:47:59 -04:00
trace-collector: Documentation
This commit is contained in:
parent
2b3e3d733c
commit
925c962945
4 changed files with 86 additions and 9 deletions
21
README.md
21
README.md
|
|
@ -26,10 +26,11 @@ MIT
|
||||||
* [x] batching, perf, etc.
|
* [x] batching, perf, etc.
|
||||||
- [ ] async collector relying on ocurl-multi
|
- [ ] async collector relying on ocurl-multi
|
||||||
- [ ] interface with `logs` (carry context around)
|
- [ ] interface with `logs` (carry context around)
|
||||||
|
- [x] implicit scope (via [ambient-context][])
|
||||||
|
|
||||||
## Use
|
## Use
|
||||||
|
|
||||||
For now, instrument manually:
|
For now, instrument traces/spans, logs, and metrics manually:
|
||||||
|
|
||||||
```ocaml
|
```ocaml
|
||||||
module Otel = Opentelemetry
|
module Otel = Opentelemetry
|
||||||
|
|
@ -45,17 +46,35 @@ let foo () =
|
||||||
]);
|
]);
|
||||||
do_more_work();
|
do_more_work();
|
||||||
()
|
()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Setup
|
||||||
|
|
||||||
|
If you're writing a top-level application, you need to perform some initial configuration.
|
||||||
|
|
||||||
|
1. Set the [`service_name`][];
|
||||||
|
2. configure our [ambient-context][] dependency with the appropriate storage for your environment — TLS, Lwt, Eio ... (see [their docs][install-ambient-storage] for more details);
|
||||||
|
3. and install a [`Collector`][] (usually by calling your collector's `with_setup` function.)
|
||||||
|
|
||||||
|
For example, if your application is using Lwt, and you're using `ocurl` as your collector, you might do something like this:
|
||||||
|
|
||||||
|
```ocaml
|
||||||
let main () =
|
let main () =
|
||||||
Otel.Globals.service_name := "my_service";
|
Otel.Globals.service_name := "my_service";
|
||||||
Otel.GC_metrics.basic_setup();
|
Otel.GC_metrics.basic_setup();
|
||||||
|
|
||||||
|
Ambient_context.with_storage_provider (Ambient_context_lwt.storage ()) @@ fun () ->
|
||||||
Opentelemetry_client_ocurl.with_setup () @@ fun () ->
|
Opentelemetry_client_ocurl.with_setup () @@ fun () ->
|
||||||
(* … *)
|
(* … *)
|
||||||
foo ();
|
foo ();
|
||||||
(* … *)
|
(* … *)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[`service_name`]: <https://v3.ocaml.org/p/opentelemetry/0.5/doc/Opentelemetry/Globals/index.html#val-service_name>
|
||||||
|
[`Collector`]: <https://v3.ocaml.org/p/opentelemetry/0.5/doc/Opentelemetry/Collector/index.html>
|
||||||
|
[ambient-context]: <https://v3.ocaml.org/p/ambient-context>
|
||||||
|
[install-ambient-storage]: <https://github.com/ELLIOTTCABLE/ocaml-ambient-context#-as-a-top-level-application>
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
The library is configurable via `Opentelemetry.Config`, via the standard
|
The library is configurable via `Opentelemetry.Config`, via the standard
|
||||||
|
|
|
||||||
|
|
@ -528,8 +528,11 @@ module Scope = struct
|
||||||
| Some _ -> scope
|
| Some _ -> scope
|
||||||
| None -> Ambient_context.get ambient_scope_key
|
| None -> Ambient_context.get ambient_scope_key
|
||||||
|
|
||||||
(** [with_ambient_scope sc f] calls [f()] in a context where [sc] is the
|
(** [with_ambient_scope sc thunk] calls [thunk()] in a context where [sc] is
|
||||||
(thread)-local scope, then reverts to the previous local scope, if any. *)
|
the (thread|continuation)-local scope, then reverts to the previous local
|
||||||
|
scope, if any.
|
||||||
|
|
||||||
|
@see <https://github.com/ELLIOTTCABLE/ocaml-ambient-context> ambient-context docs *)
|
||||||
let[@inline] with_ambient_scope (sc : t) (f : unit -> 'a) : 'a =
|
let[@inline] with_ambient_scope (sc : t) (f : unit -> 'a) : 'a =
|
||||||
Ambient_context.with_binding ambient_scope_key sc (fun _ -> f ())
|
Ambient_context.with_binding ambient_scope_key sc (fun _ -> f ())
|
||||||
end
|
end
|
||||||
|
|
@ -761,12 +764,20 @@ module Trace = struct
|
||||||
|
|
||||||
(** Sync span guard.
|
(** Sync span guard.
|
||||||
|
|
||||||
@param force_new_trace_id if true (default false), the span will not use a
|
Notably, this includes {e implicit} scope-tracking: if called without a
|
||||||
ambient scope, [scope], or [trace_id], but will always
|
[~scope] argument (or [~parent]/[~trace_id]), it will check in the
|
||||||
create a fresh new trace ID.
|
{!Ambient_context} for a surrounding environment, and use that as the
|
||||||
|
scope. Similarly, it uses {!Scope.with_ambient_scope} to {e set} a new
|
||||||
|
scope in the ambient context, so that any logically-nested calls to
|
||||||
|
{!with_} will use this span as their parent.
|
||||||
|
|
||||||
{b NOTE} be careful not to call this inside a Gc alarm, as it can
|
{b NOTE} be careful not to call this inside a Gc alarm, as it can
|
||||||
cause deadlocks. *)
|
cause deadlocks.
|
||||||
|
|
||||||
|
@param force_new_trace_id if true (default false), the span will not use a
|
||||||
|
ambient scope, the [~scope] argument, nor [~trace_id], but will instead
|
||||||
|
always create fresh identifiers for this span *)
|
||||||
|
|
||||||
let with_ ?force_new_trace_id ?trace_state ?service_name ?attrs ?kind
|
let with_ ?force_new_trace_id ?trace_state ?service_name ?attrs ?kind
|
||||||
?trace_id ?parent ?scope ?links name (cb : Scope.t -> 'a) : 'a =
|
?trace_id ?parent ?scope ?links name (cb : Scope.t -> 'a) : 'a =
|
||||||
let thunk, finally =
|
let thunk, finally =
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ module Internal = struct
|
||||||
parent_scope: Otel.Scope.t option;
|
parent_scope: Otel.Scope.t option;
|
||||||
}
|
}
|
||||||
|
|
||||||
(** Table indexed by ocaml-trace spans *)
|
|
||||||
module Active_span_tbl = Hashtbl.Make (struct
|
module Active_span_tbl = Hashtbl.Make (struct
|
||||||
include Int64
|
include Int64
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,16 @@ module Otel := Opentelemetry
|
||||||
module Otrace := Trace
|
module Otrace := Trace
|
||||||
module TLS := Ambient_context_tls.Thread_local
|
module TLS := Ambient_context_tls.Thread_local
|
||||||
|
|
||||||
|
(** [ocaml-opentelemetry.trace] implements a {!Trace_core.Collector} for {{:https://v3.ocaml.org/p/trace} ocaml-trace}.
|
||||||
|
|
||||||
|
After installing this collector with {!setup}, you can consume libraries
|
||||||
|
that use ocaml-trace, and they will automatically emit OpenTelemetry spans
|
||||||
|
and logs.
|
||||||
|
|
||||||
|
Both explicit scope (in the [_manual] functions such as [enter_manual_span])
|
||||||
|
and implicit scope (in {!Internal.M.with_span}, via {!Ambient_context}) are
|
||||||
|
supported; see the detailed notes on {!Internal.M.enter_manual_span}. *)
|
||||||
|
|
||||||
val setup : unit -> unit
|
val setup : unit -> unit
|
||||||
(** Install the OTEL backend as a Trace collector *)
|
(** Install the OTEL backend as a Trace collector *)
|
||||||
|
|
||||||
|
|
@ -22,6 +32,14 @@ module Internal : sig
|
||||||
string (* span name *) ->
|
string (* span name *) ->
|
||||||
(Otrace.span -> 'a) ->
|
(Otrace.span -> 'a) ->
|
||||||
'a
|
'a
|
||||||
|
(** Implements {!Trace_core.Collector.S.with_span}, with the OpenTelemetry
|
||||||
|
collector as the backend. Invoked via {!Trace.with_span}.
|
||||||
|
|
||||||
|
Notably, this has the same implicit-scope semantics as
|
||||||
|
{!Opentelemetry.Trace.with_}, and requires configuration of
|
||||||
|
{!Ambient_context}.
|
||||||
|
|
||||||
|
@see <https://github.com/ELLIOTTCABLE/ocaml-ambient-context> ambient-context docs *)
|
||||||
|
|
||||||
val enter_manual_span :
|
val enter_manual_span :
|
||||||
parent:Otrace.explicit_span option ->
|
parent:Otrace.explicit_span option ->
|
||||||
|
|
@ -32,8 +50,37 @@ module Internal : sig
|
||||||
data:(string * Otrace.user_data) list ->
|
data:(string * Otrace.user_data) list ->
|
||||||
string (* span name *) ->
|
string (* span name *) ->
|
||||||
Otrace.explicit_span
|
Otrace.explicit_span
|
||||||
|
(** Implements {!Trace_core.Collector.S.enter_manual_span}, with the OpenTelemetry
|
||||||
|
collector as the backend. Invoked at {!Trace.enter_manual_toplevel_span}
|
||||||
|
and {!Trace.enter_manual_sub_span}; requires an eventual call to
|
||||||
|
{!Trace.exit_manual_span}.
|
||||||
|
|
||||||
|
These 'manual span' functions {e do not} implement the same implicit-
|
||||||
|
scope semantics of {!with_span}; and thus don't need to wrap a single
|
||||||
|
stack-frame / callback; you can freely enter a span at any point, store
|
||||||
|
the returned {!Trace.explicit_span}, and exit it at any later point with
|
||||||
|
{!Trace.exit_manual_span}.
|
||||||
|
|
||||||
|
However, for that same reason, they also cannot update the
|
||||||
|
{!Ambient_context} — that is, when you invoke the various [manual]
|
||||||
|
functions, if you then invoke other functions that use
|
||||||
|
{!Trace.with_span}, those callees {e will not} see the span you entered
|
||||||
|
manually as their [parent].
|
||||||
|
|
||||||
|
Generally, the best practice is to only use these [manual] functions at
|
||||||
|
the 'leaves' of your callstack: that is, don't invoke user callbacks
|
||||||
|
from within them; or if you do, make sure to pass the [explicit_span]
|
||||||
|
you recieve from this function onwards to the user callback, so they can create further
|
||||||
|
child-spans. *)
|
||||||
|
|
||||||
val exit_manual_span : Otrace.explicit_span -> unit
|
val exit_manual_span : Otrace.explicit_span -> unit
|
||||||
|
(** Implements {!Trace_core.Collector.S.exit_manual_span}, with the
|
||||||
|
OpenTelemetry collector as the backend. Invoked at
|
||||||
|
{!Trace.exit_manual_span}. Expects the [explicit_span] returned from an
|
||||||
|
earlier call to {!Trace.enter_manual_toplevel_span} or
|
||||||
|
{!Trace.enter_manual_sub_span}.
|
||||||
|
|
||||||
|
(See the notes at {!enter_manual_span} about {!Ambient_context}.) *)
|
||||||
|
|
||||||
val message :
|
val message :
|
||||||
?span:Otrace.span ->
|
?span:Otrace.span ->
|
||||||
|
|
@ -68,6 +115,7 @@ module Internal : sig
|
||||||
|
|
||||||
module Active_span_tbl : Hashtbl.S with type key = Otrace.span
|
module Active_span_tbl : Hashtbl.S with type key = Otrace.span
|
||||||
|
|
||||||
|
(** Table indexed by ocaml-trace spans. *)
|
||||||
module Active_spans : sig
|
module Active_spans : sig
|
||||||
type t = private { tbl: span_begin Active_span_tbl.t } [@@unboxed]
|
type t = private { tbl: span_begin Active_span_tbl.t } [@@unboxed]
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue