mirror of
https://github.com/ocaml-tracing/ocaml-opentelemetry.git
synced 2026-03-08 03:47:59 -04:00
Compare commits
11 commits
b92159c11e
...
aa86fc455d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa86fc455d | ||
|
|
d57c182daa | ||
|
|
00d41b5354 | ||
|
|
aa9e3f98ff | ||
|
|
d974213376 | ||
|
|
6faf23899f | ||
|
|
068baca4c9 | ||
|
|
d77dbacfb5 | ||
|
|
6e07d48d5d | ||
|
|
e0560ac730 | ||
|
|
ba264c7094 |
19 changed files with 157 additions and 19 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -7,3 +7,6 @@ _opam
|
|||
*.install
|
||||
*.exe
|
||||
*.tmp
|
||||
src/lib/version.ml
|
||||
src/lib/.git_index_path
|
||||
src/lib/.git_index.lnk
|
||||
|
|
|
|||
32
CHANGES.md
32
CHANGES.md
|
|
@ -1,4 +1,36 @@
|
|||
|
||||
## 0.20
|
||||
|
||||
- major refactor: split library into `opentelemetry.core`, `opentelemetry`,
|
||||
`opentelemetry.util`, `opentelemetry.emitter`, `opentelemetry.atomic`, revamp internals
|
||||
- per-signal providers: separate trace, meter, and logger providers replace
|
||||
the single monolithic exporter
|
||||
- `opentelemetry.ambient-context` is now a standalone library, once again
|
||||
- new `opentelemetry-client-ocurl-lwt` package
|
||||
- client: split `opentelemetry-client-sync` off of the main client library
|
||||
- client: add support for `http/json` protocol alongside `http/protobuf`
|
||||
- client: add HTTP retry with exponential backoff
|
||||
- client: overhaul bounded queue; introduce generic consumer framework
|
||||
- client: add `Exporter_add_batching`, `Emitter_add_batching`, `Emitter_sample`,
|
||||
`Emitter_limit_interval` combinators. Batching is factored out of individual
|
||||
client libraries.
|
||||
- client: add sampler as an emitter transformer
|
||||
- client: add `exporter_stdout` and `debug_exporter`
|
||||
- client: add `self_metrics` and `self_debug` to exporters
|
||||
- client: add `after_shutdown` callback in ocurl/ocurl-lwt clients
|
||||
- `Span.dummy`: inert span that is never modified
|
||||
- `Span.record_exception` now also sets the span status to error
|
||||
- `Span.set_span_status` added in `opentelemetry.trace`
|
||||
- `Span`: carry flags to `span_link`
|
||||
- `Span`: now mutable thanks to ocaml-protoc 4.0, replaces old `Scope.t` entirely
|
||||
- `Meter.emit` and `Meter_provider.emit_l` added
|
||||
- emitter: add `flat_map`, `tap`, `to_list`, `enabled` combinators
|
||||
- clock abstraction added; `ptime` used by default in logger and metrics
|
||||
- interval limiter used for `metrics_callbacks`
|
||||
- update to OTEL spec 1.8.0
|
||||
- update semantic conventions
|
||||
- various bug fixes and performance improvements
|
||||
|
||||
## 0.12
|
||||
|
||||
- breaking: change `Collector.cleanup` so it takes a callback
|
||||
|
|
|
|||
|
|
@ -186,7 +186,8 @@ let setup_ ~sw ~config env : unit =
|
|||
|
||||
Opentelemetry.Self_debug.log Opentelemetry.Self_debug.Info (fun () ->
|
||||
"opentelemetry: cohttp-eio exporter installed");
|
||||
Opentelemetry_client.Self_trace.set_enabled config.self_trace
|
||||
Opentelemetry_client.Self_trace.set_enabled config.self_trace;
|
||||
if config.self_metrics then Opentelemetry.Sdk.setup_self_metrics ()
|
||||
|
||||
let setup ?(config = Config.make ()) ?(enable = true) ~sw env =
|
||||
if enable && not config.sdk_disabled then setup_ ~sw ~config env
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ let setup_ ~config () : unit =
|
|||
Opentelemetry.Self_debug.log Opentelemetry.Self_debug.Info (fun () ->
|
||||
"opentelemetry: cohttp-lwt exporter installed");
|
||||
Opentelemetry_client.Self_trace.set_enabled config.self_trace;
|
||||
if config.self_metrics then Opentelemetry.Sdk.setup_self_metrics ();
|
||||
()
|
||||
|
||||
let setup ?(config = Config.make ()) ?(enable = true) () =
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ let setup_ ~config () : Exporter.t =
|
|||
Opentelemetry.Self_debug.log Opentelemetry.Self_debug.Info (fun () ->
|
||||
"opentelemetry: ocurl-lwt exporter installed");
|
||||
Opentelemetry_client.Self_trace.set_enabled config.self_trace;
|
||||
if config.self_metrics then Opentelemetry.Sdk.setup_self_metrics ();
|
||||
|
||||
exp
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ let setup_ ~config () : OTEL.Exporter.t =
|
|||
"opentelemetry: ocurl exporter installed");
|
||||
|
||||
OTELC.Self_trace.set_enabled config.common.self_trace;
|
||||
if config.common.self_metrics then Opentelemetry.Sdk.setup_self_metrics ();
|
||||
exporter
|
||||
|
||||
let remove_exporter () : unit =
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ type t = {
|
|||
metrics: Opentelemetry.Provider_config.t;
|
||||
logs: Opentelemetry.Provider_config.t;
|
||||
self_trace: bool;
|
||||
self_metrics: bool;
|
||||
http_concurrency_level: int option;
|
||||
retry_max_attempts: int;
|
||||
retry_initial_delay_ms: float;
|
||||
|
|
@ -65,6 +66,7 @@ let pp out (self : t) : unit =
|
|||
log_level;
|
||||
sdk_disabled;
|
||||
self_trace;
|
||||
self_metrics;
|
||||
url_traces;
|
||||
url_metrics;
|
||||
url_logs;
|
||||
|
|
@ -91,7 +93,8 @@ let pp out (self : t) : unit =
|
|||
in
|
||||
Format.fprintf out
|
||||
"{@[ debug=%B;@ log_level=%a;@ sdk_disabled=%B;@ self_trace=%B;@ \
|
||||
url_traces=%S;@ url_metrics=%S;@ url_logs=%S;@ @[<2>headers=@,\
|
||||
self_metrics=%B;@ url_traces=%S;@ url_metrics=%S;@ url_logs=%S;@ \
|
||||
@[<2>headers=@,\
|
||||
%a@];@ @[<2>headers_traces=@,\
|
||||
%a@];@ @[<2>headers_metrics=@,\
|
||||
%a@];@ @[<2>headers_logs=@,\
|
||||
|
|
@ -100,8 +103,8 @@ let pp out (self : t) : unit =
|
|||
logs=%a;@ http_concurrency_level=%a;@ retry_max_attempts=%d;@ \
|
||||
retry_initial_delay_ms=%.0f;@ retry_max_delay_ms=%.0f;@ \
|
||||
retry_backoff_multiplier=%.1f @]}"
|
||||
debug pp_log_level log_level sdk_disabled self_trace url_traces url_metrics
|
||||
url_logs ppheaders headers ppheaders headers_traces ppheaders
|
||||
debug pp_log_level log_level sdk_disabled self_trace self_metrics url_traces
|
||||
url_metrics url_logs ppheaders headers ppheaders headers_traces ppheaders
|
||||
headers_metrics ppheaders headers_logs pp_protocol protocol timeout_ms
|
||||
timeout_traces_ms timeout_metrics_ms timeout_logs_ms pp_provider_config
|
||||
traces pp_provider_config metrics pp_provider_config logs ppiopt
|
||||
|
|
@ -135,6 +138,7 @@ type 'k make =
|
|||
?timeout_metrics_ms:int ->
|
||||
?timeout_logs_ms:int ->
|
||||
?self_trace:bool ->
|
||||
?self_metrics:bool ->
|
||||
?http_concurrency_level:int ->
|
||||
?retry_max_attempts:int ->
|
||||
?retry_initial_delay_ms:float ->
|
||||
|
|
@ -245,9 +249,9 @@ module Env () : ENV = struct
|
|||
?(protocol = get_protocol_from_env "OTEL_EXPORTER_OTLP_PROTOCOL")
|
||||
?(timeout_ms = get_timeout_from_env "OTEL_EXPORTER_OTLP_TIMEOUT" 10_000)
|
||||
?timeout_traces_ms ?timeout_metrics_ms ?timeout_logs_ms
|
||||
?(self_trace = false) ?http_concurrency_level ?(retry_max_attempts = 3)
|
||||
?(retry_initial_delay_ms = 100.) ?(retry_max_delay_ms = 5000.)
|
||||
?(retry_backoff_multiplier = 2.0) =
|
||||
?(self_trace = false) ?(self_metrics = false) ?http_concurrency_level
|
||||
?(retry_max_attempts = 3) ?(retry_initial_delay_ms = 100.)
|
||||
?(retry_max_delay_ms = 5000.) ?(retry_backoff_multiplier = 2.0) =
|
||||
let batch_timeout_ = Mtime.Span.(batch_timeout_ms * ms) in
|
||||
let traces =
|
||||
match traces with
|
||||
|
|
@ -375,6 +379,7 @@ module Env () : ENV = struct
|
|||
metrics;
|
||||
logs;
|
||||
self_trace;
|
||||
self_metrics;
|
||||
http_concurrency_level;
|
||||
retry_max_attempts;
|
||||
retry_initial_delay_ms;
|
||||
|
|
|
|||
|
|
@ -72,6 +72,10 @@ type t = {
|
|||
(** If true, the OTEL library will perform some self-instrumentation.
|
||||
Default [false].
|
||||
@since 0.7 *)
|
||||
self_metrics: bool;
|
||||
(** If true, the OTEL library will regularly emit metrics about itself.
|
||||
Default [false].
|
||||
@since NEXT_RELEASE *)
|
||||
http_concurrency_level: int option;
|
||||
(** How many HTTP requests can be done simultaneously (at most)? This can
|
||||
be used to represent the size of a pool of workers where each worker
|
||||
|
|
@ -123,6 +127,7 @@ type 'k make =
|
|||
?timeout_metrics_ms:int ->
|
||||
?timeout_logs_ms:int ->
|
||||
?self_trace:bool ->
|
||||
?self_metrics:bool ->
|
||||
?http_concurrency_level:int ->
|
||||
?retry_max_attempts:int ->
|
||||
?retry_initial_delay_ms:float ->
|
||||
|
|
|
|||
|
|
@ -2,14 +2,19 @@
|
|||
|
||||
open Common_
|
||||
|
||||
open struct
|
||||
let mk_resources ?service_name ?attrs () =
|
||||
let attributes = OTEL.Globals.mk_attributes ?service_name ?attrs () in
|
||||
Proto.Resource.make_resource ~attributes ()
|
||||
end
|
||||
|
||||
let make_resource_logs ?service_name ?attrs (logs : Proto.Logs.log_record list)
|
||||
: Proto.Logs.resource_logs =
|
||||
let attributes = OTEL.Globals.mk_attributes ?service_name ?attrs () in
|
||||
let resource = Proto.Resource.make_resource ~attributes () in
|
||||
let ll =
|
||||
Proto.Logs.make_scope_logs ~scope:OTEL.Globals.instrumentation_library
|
||||
~log_records:logs ()
|
||||
in
|
||||
let resource = mk_resources ?service_name ?attrs () in
|
||||
Proto.Logs.make_resource_logs ~resource ~scope_logs:[ ll ] ()
|
||||
|
||||
let make_resource_spans ?service_name ?attrs spans : Proto.Trace.resource_spans
|
||||
|
|
@ -18,8 +23,7 @@ let make_resource_spans ?service_name ?attrs spans : Proto.Trace.resource_spans
|
|||
Proto.Trace.make_scope_spans ~scope:OTEL.Globals.instrumentation_library
|
||||
~spans ()
|
||||
in
|
||||
let attributes = OTEL.Globals.mk_attributes ?service_name ?attrs () in
|
||||
let resource = Proto.Resource.make_resource ~attributes () in
|
||||
let resource = mk_resources ?service_name ?attrs () in
|
||||
Proto.Trace.make_resource_spans ~resource ~scope_spans:[ ils ] ()
|
||||
|
||||
(** Aggregate metrics into a {!Proto.Metrics.resource_metrics} *)
|
||||
|
|
@ -29,6 +33,5 @@ let make_resource_metrics ?service_name ?attrs (l : OTEL.Metrics.t list) :
|
|||
let lm =
|
||||
make_scope_metrics ~scope:OTEL.Globals.instrumentation_library ~metrics:l ()
|
||||
in
|
||||
let attributes = OTEL.Globals.mk_attributes ?service_name ?attrs () in
|
||||
let resource = Proto.Resource.make_resource ~attributes () in
|
||||
let resource = mk_resources ?service_name ?attrs () in
|
||||
Proto.Metrics.make_resource_metrics ~scope_metrics:[ lm ] ~resource ()
|
||||
|
|
|
|||
24
src/lib/dune
24
src/lib/dune
|
|
@ -1,3 +1,26 @@
|
|||
(rule
|
||||
(target .git_index_path)
|
||||
(deps (universe) gen_git_index_path.sh)
|
||||
(action
|
||||
(with-stdout-to
|
||||
.git_index_path
|
||||
(run sh gen_git_index_path.sh))))
|
||||
|
||||
(rule
|
||||
(target .git_index.lnk)
|
||||
(action
|
||||
(run ln -sf %{read-lines:.git_index_path} %{target})))
|
||||
|
||||
(rule
|
||||
(target version.ml)
|
||||
(deps
|
||||
(file .git_index.lnk)
|
||||
gen_version.sh)
|
||||
(action
|
||||
(with-stdout-to
|
||||
version.ml
|
||||
(run sh gen_version.sh))))
|
||||
|
||||
(library
|
||||
(name opentelemetry)
|
||||
(public_name opentelemetry)
|
||||
|
|
@ -24,4 +47,5 @@
|
|||
mtime
|
||||
mtime.clock.os
|
||||
pbrt
|
||||
unix
|
||||
threads))
|
||||
|
|
|
|||
2
src/lib/gen_git_index_path.sh
Normal file
2
src/lib/gen_git_index_path.sh
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
git rev-parse --git-path index 2>/dev/null || echo /dev/null
|
||||
6
src/lib/gen_version.sh
Normal file
6
src/lib/gen_version.sh
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
v=$(git describe --exact-match HEAD 2>/dev/null | sed 's/^v//')
|
||||
[ -z "$v" ] && v=dev
|
||||
h=$(git rev-parse HEAD 2>/dev/null)
|
||||
[ -z "$h" ] && h=unknown
|
||||
printf 'let version = "%s"\nlet git_hash = "%s"\n' "$v" "$h"
|
||||
|
|
@ -20,8 +20,11 @@ let service_instance_id = ref None
|
|||
@since 0.12 *)
|
||||
let service_version = ref None
|
||||
|
||||
(** @since NEXT_RELEASE *)
|
||||
let sdk_version : string = Version.(spf "%s at %s" version git_hash)
|
||||
|
||||
let instrumentation_library =
|
||||
make_instrumentation_scope ~version:"%%VERSION_NUM%%" ~name:"ocaml-otel" ()
|
||||
make_instrumentation_scope ~version:sdk_version ~name:"opentelemetry" ()
|
||||
|
||||
(** Global attributes, initially set via OTEL_RESOURCE_ATTRIBUTES and modifiable
|
||||
by the user code. They will be attached to each outgoing metrics/traces. *)
|
||||
|
|
@ -58,6 +61,15 @@ open struct
|
|||
]
|
||||
|
||||
let runtime_attributes_converted = List.map Key_value.conv runtime_attributes
|
||||
|
||||
let sdk_attributes =
|
||||
[
|
||||
"telemetry.sdk.language", `String "ocaml";
|
||||
"telemetry.sdk.name", `String "opentelemetry";
|
||||
"telemetry.sdk.version", `String sdk_version;
|
||||
]
|
||||
|
||||
let sdk_attributes_converted = List.map Key_value.conv sdk_attributes
|
||||
end
|
||||
|
||||
(** Attributes about the OCaml runtime. See
|
||||
|
|
@ -65,9 +77,12 @@ end
|
|||
*)
|
||||
let[@inline] get_runtime_attributes () = runtime_attributes
|
||||
|
||||
(** Build main global attributes, to be used in resource attributes (shared by
|
||||
all spans/metrics/logs in each outgoing batch) *)
|
||||
let mk_attributes ?(service_name = !service_name) ?(attrs = []) () : _ list =
|
||||
let l = List.rev_map Key_value.conv attrs in
|
||||
let l = List.rev_append runtime_attributes_converted l in
|
||||
let l = List.rev_append sdk_attributes_converted l in
|
||||
let l =
|
||||
make_key_value ~key:Conventions.Attributes.Service.name
|
||||
~value:(String_value service_name) ()
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ type key_value = Key_value.t
|
|||
(** {2 Global settings} *)
|
||||
|
||||
module Globals = Globals
|
||||
module Version = Version
|
||||
|
||||
(** {2 Traces and Spans} *)
|
||||
|
||||
|
|
|
|||
|
|
@ -90,9 +90,35 @@ let set ?(traces = Provider_config.default) ?(metrics = Provider_config.default)
|
|||
Log_provider.set logger
|
||||
|
||||
let self_metrics () : Metrics.t list =
|
||||
let now = Clock.now_main () in
|
||||
let emitter_metrics =
|
||||
Emitter.self_metrics (Trace_provider.get ()).emit ~now
|
||||
@ Emitter.self_metrics (Meter_provider.get ()).emit ~now
|
||||
@ Emitter.self_metrics (Log_provider.get ()).emit ~now
|
||||
in
|
||||
match get () with
|
||||
| None -> []
|
||||
| Some exp -> exp.Exporter.self_metrics ()
|
||||
| None -> emitter_metrics
|
||||
| Some exp -> exp.Exporter.self_metrics () @ emitter_metrics
|
||||
|
||||
open struct
|
||||
let self_metrics_enabled = Atomic.make false
|
||||
end
|
||||
|
||||
(** Regularly emit metrics about the OTEL SDK. Idempotent. *)
|
||||
let setup_self_metrics () =
|
||||
if not (Atomic.exchange self_metrics_enabled true) then (
|
||||
Self_debug.log Info (fun () -> "enabling self metrics");
|
||||
let interval_limiter =
|
||||
Interval_limiter.create ~min_interval:Mtime.Span.(10 * s) ()
|
||||
in
|
||||
let on_tick () =
|
||||
if Interval_limiter.make_attempt interval_limiter then (
|
||||
let ms = self_metrics () in
|
||||
Meter_provider.emit_l ms
|
||||
)
|
||||
in
|
||||
Globals.add_on_tick_callback on_tick
|
||||
)
|
||||
|
||||
(* Permanent tick callback to drive batch timeouts on provider emitters *)
|
||||
let () =
|
||||
|
|
|
|||
7
src/lib/version.mli
Normal file
7
src/lib/version.mli
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
val version : string
|
||||
(** Version of the library, e.g. ["0.12"]. ["dev"] if not built from a release
|
||||
tag. *)
|
||||
|
||||
val git_hash : string
|
||||
(** Full git commit hash at build time, e.g. ["b92159c1..."]. ["unknown"] if git
|
||||
was unavailable. *)
|
||||
|
|
@ -8,7 +8,7 @@ let test_config_printing () =
|
|||
in
|
||||
let expected =
|
||||
"{ debug=false; log_level=info; sdk_disabled=false; self_trace=false;\n\
|
||||
\ url_traces=\"http://localhost:4318/v1/traces\";\n\
|
||||
\ self_metrics=false; url_traces=\"http://localhost:4318/v1/traces\";\n\
|
||||
\ url_metrics=\"http://localhost:4318/v1/metrics\";\n\
|
||||
\ url_logs=\"http://localhost:4318/v1/logs\"; headers=[]; headers_traces=[];\n\
|
||||
\ headers_metrics=[]; headers_logs=[]; protocol=http/protobuf;\n\
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@
|
|||
scope_logs =
|
||||
[{ scope =
|
||||
Some(
|
||||
{ name = "ocaml-otel";
|
||||
version = "%%VERSION_NUM%%";
|
||||
{ name = "opentelemetry";
|
||||
version = "";
|
||||
attributes = [];
|
||||
dropped_attributes_count = 0 (* absent *);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -42,6 +42,11 @@ let tests (signal_batches : Client.Resource_signal.t list) =
|
|||
lr)
|
||||
sl.log_records
|
||||
in
|
||||
Option.iter
|
||||
(fun sc ->
|
||||
Opentelemetry_proto.Common
|
||||
.instrumentation_scope_set_version sc "")
|
||||
sl.scope;
|
||||
let sl = L.copy_scope_logs sl in
|
||||
L.scope_logs_set_log_records sl masked_log_records;
|
||||
sl)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue