mirror of
https://github.com/ocaml-tracing/ocaml-opentelemetry.git
synced 2026-03-09 12:23:32 -04:00
wip: trace
This commit is contained in:
parent
bd335ecadd
commit
2170c16e7f
2 changed files with 33 additions and 196 deletions
|
|
@ -50,57 +50,30 @@ end
|
||||||
|
|
||||||
open Conv
|
open Conv
|
||||||
|
|
||||||
module Well_known = struct
|
|
||||||
let spankind_key = "otrace.spankind"
|
|
||||||
|
|
||||||
let internal = `String "INTERNAL"
|
|
||||||
|
|
||||||
let server = `String "SERVER"
|
|
||||||
|
|
||||||
let client = `String "CLIENT"
|
|
||||||
|
|
||||||
let producer = `String "PRODUCER"
|
|
||||||
|
|
||||||
let consumer = `String "CONSUMER"
|
|
||||||
|
|
||||||
let spankind_of_string =
|
|
||||||
let open Otel.Span in
|
|
||||||
function
|
|
||||||
| "INTERNAL" -> Span_kind_internal
|
|
||||||
| "SERVER" -> Span_kind_server
|
|
||||||
| "CLIENT" -> Span_kind_client
|
|
||||||
| "PRODUCER" -> Span_kind_producer
|
|
||||||
| "CONSUMER" -> Span_kind_consumer
|
|
||||||
| _ -> Span_kind_unspecified
|
|
||||||
|
|
||||||
let otel_attrs_of_otrace_data data =
|
|
||||||
let kind : Otel.Span.kind ref = ref Otel.Span.Span_kind_unspecified in
|
|
||||||
let data =
|
|
||||||
List.filter_map
|
|
||||||
(function
|
|
||||||
| name, `String v when name = "otrace.spankind" ->
|
|
||||||
kind := spankind_of_string v;
|
|
||||||
None
|
|
||||||
| x -> Some x)
|
|
||||||
data
|
|
||||||
in
|
|
||||||
!kind, data
|
|
||||||
|
|
||||||
(** Key to store an error [Otel.Span.status] with the message. Set
|
|
||||||
["otrace.error" = "mymsg"] in a span data to set the span's status to
|
|
||||||
[{message="mymsg"; code=Error}]. *)
|
|
||||||
let status_error_key = "otrace.error"
|
|
||||||
end
|
|
||||||
|
|
||||||
open Well_known
|
|
||||||
|
|
||||||
let on_internal_error =
|
let on_internal_error =
|
||||||
ref (fun msg -> Printf.eprintf "error in Opentelemetry_trace: %s\n%!" msg)
|
ref (fun msg -> Printf.eprintf "error in Opentelemetry_trace: %s\n%!" msg)
|
||||||
|
|
||||||
type Otrace.extension_event +=
|
module Extensions = struct
|
||||||
| Ev_link_span of Otrace.explicit_span * Otrace.explicit_span
|
type Otrace.extension_event +=
|
||||||
| Ev_set_span_kind of Otrace.explicit_span * Otel.Span_kind.t
|
| Ev_link_span of Otrace.explicit_span * Otrace.explicit_span
|
||||||
| Ev_record_exn of Otrace.explicit_span * exn * Printexc.raw_backtrace
|
| Ev_record_exn of Otrace.explicit_span * exn * Printexc.raw_backtrace
|
||||||
|
| Ev_set_span_kind of Otrace.explicit_span * Otel.Span_kind.t
|
||||||
|
end
|
||||||
|
|
||||||
|
open Extensions
|
||||||
|
module Span_tbl = Trace_subscriber.Span_tbl
|
||||||
|
|
||||||
|
(* TODO: subscriber
|
||||||
|
type state = {
|
||||||
|
foo: unit (* TODO: *)
|
||||||
|
}
|
||||||
|
|
||||||
|
module Callbacks
|
||||||
|
*)
|
||||||
|
|
||||||
|
let subscriber_of_exporter _ = assert false
|
||||||
|
|
||||||
|
let collector_of_exporter _ = assert false
|
||||||
|
|
||||||
module Internal = struct
|
module Internal = struct
|
||||||
type span_begin = {
|
type span_begin = {
|
||||||
|
|
@ -190,7 +163,8 @@ module Internal = struct
|
||||||
{ start_time; name; __FILE__; __LINE__; __FUNCTION__; scope; parent } =
|
{ start_time; name; __FILE__; __LINE__; __FUNCTION__; scope; parent } =
|
||||||
let open Otel in
|
let open Otel in
|
||||||
let end_time = Timestamp_ns.now_unix_ns () in
|
let end_time = Timestamp_ns.now_unix_ns () in
|
||||||
let kind, attrs = otel_attrs_of_otrace_data (Scope.attrs scope) in
|
let kind = Scope.kind scope in
|
||||||
|
let attrs = Scope.attrs scope in
|
||||||
|
|
||||||
let status : Span_status.t =
|
let status : Span_status.t =
|
||||||
match List.assoc_opt Well_known.status_error_key attrs with
|
match List.assoc_opt Well_known.status_error_key attrs with
|
||||||
|
|
|
||||||
|
|
@ -9,26 +9,13 @@
|
||||||
and implicit scope (in {!Internal.M.with_span}, via {!Ambient_context}) are
|
and implicit scope (in {!Internal.M.with_span}, via {!Ambient_context}) are
|
||||||
supported; see the detailed notes on {!Internal.M.enter_manual_span}.
|
supported; see the detailed notes on {!Internal.M.enter_manual_span}.
|
||||||
|
|
||||||
{1:wellknown Well-known identifiers}
|
We use [Trace_core.extension_event] to add more features on top of the
|
||||||
|
common tracing interface. For example to set the "span kind":
|
||||||
Because [ocaml-trace]'s API is a subset of OpenTelemetry functionality, this
|
|
||||||
interface allows for a few 'well-known' identifiers to be used in
|
|
||||||
[Trace]-instrumented libraries that wish to further support OpenTelemetry
|
|
||||||
usage.
|
|
||||||
|
|
||||||
(These strings will not change in subsequent versions of this library, so
|
|
||||||
you do not need to depend on [opentelemetry.trace] to use them.)
|
|
||||||
|
|
||||||
- If a key of exactly ["otrace.spankind"] is included in the
|
|
||||||
{!Trace_core.user_data} passed to [with_span] et al., it will be used as
|
|
||||||
the {!Opentelemetry.Span.kind} of the emitted span. (See
|
|
||||||
{!Internal.spankind_of_string} for the list of supported values.)
|
|
||||||
|
|
||||||
{[
|
{[
|
||||||
let describe () = [ Opentelemetry_trace.(spankind_key, client) ] in
|
let@ span = Trace_core.with_span ~__FILE__ ~__LINE__ "my-span" in
|
||||||
Trace_core.with_span ~__FILE__ ~__LINE__ ~data:describe "my-span"
|
Opentelemetry_trace.set_span_kind span Span_kind_client
|
||||||
@@ fun _ ->
|
(* ... *)
|
||||||
(* ... *)
|
|
||||||
]} *)
|
]} *)
|
||||||
|
|
||||||
module Otel := Opentelemetry
|
module Otel := Opentelemetry
|
||||||
|
|
@ -78,7 +65,12 @@ val setup_with_otel_exporter : #Opentelemetry.Exporter.t -> unit
|
||||||
val setup_with_otel_backend : #Opentelemetry.Exporter.t -> unit
|
val setup_with_otel_backend : #Opentelemetry.Exporter.t -> unit
|
||||||
[@@deprecated "use setup_with_otel_exporter"]
|
[@@deprecated "use setup_with_otel_exporter"]
|
||||||
|
|
||||||
|
val subscriber_of_exporter : #Otel.Exporter.t -> Trace_subscriber.t
|
||||||
|
|
||||||
|
val collector_of_exporter : #Otel.Exporter.t -> Trace_core.collector
|
||||||
|
|
||||||
val collector : unit -> Trace_core.collector
|
val collector : unit -> Trace_core.collector
|
||||||
|
[@@deprecated "use collector_of_exporter, avoid global state"]
|
||||||
(** Make a Trace collector that uses the OTEL backend to send spans and logs *)
|
(** Make a Trace collector that uses the OTEL backend to send spans and logs *)
|
||||||
|
|
||||||
val link_spans : Otrace.explicit_span -> Otrace.explicit_span -> unit
|
val link_spans : Otrace.explicit_span -> Otrace.explicit_span -> unit
|
||||||
|
|
@ -115,132 +107,3 @@ module Well_known : sig
|
||||||
Otel.Span.kind * Otel.Span.key_value list
|
Otel.Span.kind * Otel.Span.key_value list
|
||||||
end
|
end
|
||||||
[@@deprecated "use the regular functions for this"]
|
[@@deprecated "use the regular functions for this"]
|
||||||
|
|
||||||
(**/**)
|
|
||||||
|
|
||||||
(** Internal implementation details; do not consider these stable. *)
|
|
||||||
module Internal : sig
|
|
||||||
module M : sig
|
|
||||||
val with_span :
|
|
||||||
__FUNCTION__:string option ->
|
|
||||||
__FILE__:string ->
|
|
||||||
__LINE__:int ->
|
|
||||||
data:(string * Otrace.user_data) list ->
|
|
||||||
string (* span name *) ->
|
|
||||||
(Otrace.span -> 'a) ->
|
|
||||||
'a
|
|
||||||
(** Implements {!Trace_core.Collector.S.with_span}, with the OpenTelemetry
|
|
||||||
collector as the backend. Invoked via {!Trace_core.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_ctx option ->
|
|
||||||
flavor:'a ->
|
|
||||||
__FUNCTION__:string option ->
|
|
||||||
__FILE__:string ->
|
|
||||||
__LINE__:int ->
|
|
||||||
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_core.enter_manual_toplevel_span} and
|
|
||||||
{!Trace_core.enter_manual_sub_span}; requires an eventual call to
|
|
||||||
{!Trace_core.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_core.explicit_span}, and exit it at any later point
|
|
||||||
with {!Trace_core.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_core.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_core.exit_manual_span}. Expects the [explicit_span] returned
|
|
||||||
from an earlier call to {!Trace_core.enter_manual_toplevel_span} or
|
|
||||||
{!Trace_core.enter_manual_sub_span}.
|
|
||||||
|
|
||||||
(See the notes at {!enter_manual_span} about {!Ambient_context}.) *)
|
|
||||||
|
|
||||||
val add_data_to_span :
|
|
||||||
Otrace.span -> (string * Otrace.user_data) list -> unit
|
|
||||||
|
|
||||||
val add_data_to_manual_span :
|
|
||||||
Otrace.explicit_span -> (string * Otrace.user_data) list -> unit
|
|
||||||
|
|
||||||
val message :
|
|
||||||
?span:Otrace.span ->
|
|
||||||
data:(string * Otrace.user_data) list ->
|
|
||||||
string ->
|
|
||||||
unit
|
|
||||||
|
|
||||||
val shutdown : unit -> unit
|
|
||||||
|
|
||||||
val name_process : string -> unit
|
|
||||||
|
|
||||||
val name_thread : string -> unit
|
|
||||||
|
|
||||||
val counter_int :
|
|
||||||
data:(string * Otrace.user_data) list -> string -> int -> unit
|
|
||||||
|
|
||||||
val counter_float :
|
|
||||||
data:(string * Otrace.user_data) list -> string -> float -> unit
|
|
||||||
end
|
|
||||||
|
|
||||||
type span_begin = {
|
|
||||||
start_time: int64;
|
|
||||||
name: string;
|
|
||||||
__FILE__: string;
|
|
||||||
__LINE__: int;
|
|
||||||
__FUNCTION__: string option;
|
|
||||||
scope: Otel.Scope.t;
|
|
||||||
parent: Otel.Span_ctx.t option;
|
|
||||||
}
|
|
||||||
|
|
||||||
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]
|
|
||||||
|
|
||||||
val create : unit -> t
|
|
||||||
|
|
||||||
val k_tls : t TLS.t
|
|
||||||
|
|
||||||
val get : unit -> t
|
|
||||||
end
|
|
||||||
|
|
||||||
val otrace_of_otel : Otel.Span_id.t -> Otrace.span
|
|
||||||
|
|
||||||
val enter_span' :
|
|
||||||
?explicit_parent:Otrace.explicit_span_ctx ->
|
|
||||||
__FUNCTION__:string option ->
|
|
||||||
__FILE__:string ->
|
|
||||||
__LINE__:int ->
|
|
||||||
data:(string * Otrace.user_data) list ->
|
|
||||||
string ->
|
|
||||||
Otrace.span * span_begin
|
|
||||||
|
|
||||||
val exit_span' : Otrace.span -> span_begin -> Otel.Span.t
|
|
||||||
end
|
|
||||||
|
|
||||||
(**/**)
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue