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
|
||||
|
||||
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 =
|
||||
ref (fun msg -> Printf.eprintf "error in Opentelemetry_trace: %s\n%!" msg)
|
||||
|
||||
type Otrace.extension_event +=
|
||||
module Extensions = struct
|
||||
type Otrace.extension_event +=
|
||||
| Ev_link_span of Otrace.explicit_span * Otrace.explicit_span
|
||||
| Ev_set_span_kind of Otrace.explicit_span * Otel.Span_kind.t
|
||||
| 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
|
||||
type span_begin = {
|
||||
|
|
@ -190,7 +163,8 @@ module Internal = struct
|
|||
{ start_time; name; __FILE__; __LINE__; __FUNCTION__; scope; parent } =
|
||||
let open Otel 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 =
|
||||
match List.assoc_opt Well_known.status_error_key attrs with
|
||||
|
|
|
|||
|
|
@ -9,25 +9,12 @@
|
|||
and implicit scope (in {!Internal.M.with_span}, via {!Ambient_context}) are
|
||||
supported; see the detailed notes on {!Internal.M.enter_manual_span}.
|
||||
|
||||
{1:wellknown Well-known identifiers}
|
||||
|
||||
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.)
|
||||
We use [Trace_core.extension_event] to add more features on top of the
|
||||
common tracing interface. For example to set the "span kind":
|
||||
|
||||
{[
|
||||
let describe () = [ Opentelemetry_trace.(spankind_key, client) ] in
|
||||
Trace_core.with_span ~__FILE__ ~__LINE__ ~data:describe "my-span"
|
||||
@@ fun _ ->
|
||||
let@ span = Trace_core.with_span ~__FILE__ ~__LINE__ "my-span" in
|
||||
Opentelemetry_trace.set_span_kind span Span_kind_client
|
||||
(* ... *)
|
||||
]} *)
|
||||
|
||||
|
|
@ -78,7 +65,12 @@ val setup_with_otel_exporter : #Opentelemetry.Exporter.t -> unit
|
|||
val setup_with_otel_backend : #Opentelemetry.Exporter.t -> unit
|
||||
[@@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
|
||||
[@@deprecated "use collector_of_exporter, avoid global state"]
|
||||
(** Make a Trace collector that uses the OTEL backend to send spans and logs *)
|
||||
|
||||
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
|
||||
end
|
||||
[@@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