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.
|
||||
- [ ] async collector relying on ocurl-multi
|
||||
- [ ] interface with `logs` (carry context around)
|
||||
- [x] implicit scope (via [ambient-context][])
|
||||
|
||||
## Use
|
||||
|
||||
For now, instrument manually:
|
||||
For now, instrument traces/spans, logs, and metrics manually:
|
||||
|
||||
```ocaml
|
||||
module Otel = Opentelemetry
|
||||
|
|
@ -45,17 +46,35 @@ let foo () =
|
|||
]);
|
||||
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 () =
|
||||
Otel.Globals.service_name := "my_service";
|
||||
Otel.GC_metrics.basic_setup();
|
||||
|
||||
Ambient_context.with_storage_provider (Ambient_context_lwt.storage ()) @@ fun () ->
|
||||
Opentelemetry_client_ocurl.with_setup () @@ fun () ->
|
||||
(* … *)
|
||||
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
|
||||
|
||||
The library is configurable via `Opentelemetry.Config`, via the standard
|
||||
|
|
|
|||
|
|
@ -528,8 +528,11 @@ module Scope = struct
|
|||
| Some _ -> scope
|
||||
| None -> Ambient_context.get ambient_scope_key
|
||||
|
||||
(** [with_ambient_scope sc f] calls [f()] in a context where [sc] is the
|
||||
(thread)-local scope, then reverts to the previous local scope, if any. *)
|
||||
(** [with_ambient_scope sc thunk] calls [thunk()] in a context where [sc] is
|
||||
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 =
|
||||
Ambient_context.with_binding ambient_scope_key sc (fun _ -> f ())
|
||||
end
|
||||
|
|
@ -761,12 +764,20 @@ module Trace = struct
|
|||
|
||||
(** Sync span guard.
|
||||
|
||||
@param force_new_trace_id if true (default false), the span will not use a
|
||||
ambient scope, [scope], or [trace_id], but will always
|
||||
create a fresh new trace ID.
|
||||
Notably, this includes {e implicit} scope-tracking: if called without a
|
||||
[~scope] argument (or [~parent]/[~trace_id]), it will check in the
|
||||
{!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
|
||||
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
|
||||
?trace_id ?parent ?scope ?links name (cb : Scope.t -> 'a) : 'a =
|
||||
let thunk, finally =
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ module Internal = struct
|
|||
parent_scope: Otel.Scope.t option;
|
||||
}
|
||||
|
||||
(** Table indexed by ocaml-trace spans *)
|
||||
module Active_span_tbl = Hashtbl.Make (struct
|
||||
include Int64
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,16 @@ module Otel := Opentelemetry
|
|||
module Otrace := Trace
|
||||
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
|
||||
(** Install the OTEL backend as a Trace collector *)
|
||||
|
||||
|
|
@ -22,6 +32,14 @@ module Internal : sig
|
|||
string (* span name *) ->
|
||||
(Otrace.span -> '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 :
|
||||
parent:Otrace.explicit_span option ->
|
||||
|
|
@ -32,8 +50,37 @@ module Internal : sig
|
|||
data:(string * Otrace.user_data) list ->
|
||||
string (* span name *) ->
|
||||
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
|
||||
(** 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 :
|
||||
?span:Otrace.span ->
|
||||
|
|
@ -68,6 +115,7 @@ module Internal : sig
|
|||
|
||||
module Active_span_tbl : Hashtbl.S with type key = Otrace.span
|
||||
|
||||
(** Table indexed by ocaml-trace spans. *)
|
||||
module Active_spans : sig
|
||||
type t = private { tbl: span_begin Active_span_tbl.t } [@@unboxed]
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue