diff --git a/dune-project b/dune-project index 94dc1983..fdf44523 100644 --- a/dune-project +++ b/dune-project @@ -18,6 +18,7 @@ (ocaml (>= "4.08")) ptime (odoc :with-doc) + (ocaml-protoc (>= 2.2)) (pbrt (>= 2.2))) (tags (instrumentation tracing opentelemetry datadog jaeger))) @@ -41,6 +42,7 @@ (mtime (>= "1.4")) ; for spans ; atomic ; vendored (opentelemetry (= :version)) + (ocaml-protoc (>= 2.2)) (pbrt (>= 2.2)) (odoc :with-doc) ocurl) diff --git a/opentelemetry-client-ocurl.opam b/opentelemetry-client-ocurl.opam index 93413858..50f000a4 100644 --- a/opentelemetry-client-ocurl.opam +++ b/opentelemetry-client-ocurl.opam @@ -13,6 +13,7 @@ depends: [ "ocaml" {>= "4.08"} "mtime" {>= "1.4"} "opentelemetry" {= version} + "ocaml-protoc" {>= "2.2"} "pbrt" {>= "2.2"} "odoc" {with-doc} "ocurl" diff --git a/opentelemetry.opam b/opentelemetry.opam index e93e6eba..bf6ae3b9 100644 --- a/opentelemetry.opam +++ b/opentelemetry.opam @@ -14,6 +14,7 @@ depends: [ "ocaml" {>= "4.08"} "ptime" "odoc" {with-doc} + "ocaml-protoc" {>= "2.2"} "pbrt" {>= "2.2"} ] build: [ diff --git a/src/client/common_.ml b/src/client/common_.ml index 5b9a0010..4ad77233 100644 --- a/src/client/common_.ml +++ b/src/client/common_.ml @@ -27,22 +27,13 @@ let parse_headers s = let parse_header s = Scanf.sscanf s "%s@=%s" (fun key value -> key, value) in String.split_on_char ',' s |> List.map parse_header -let default_url = "http://localhost:4318" - let default_headers = [] -let url = - ref (try Sys.getenv "OTEL_EXPORTER_OTLP_ENDPOINT" with _ -> default_url) - let headers = ref (try parse_headers (Sys.getenv "OTEL_EXPORTER_OTLP_HEADERS") with _ -> default_headers) -let get_url () = !url - -let set_url s = url := s - let get_headers () = !headers let set_headers s = headers := s diff --git a/src/client/config.ml b/src/client/config.ml index 5018173a..3c204946 100644 --- a/src/client/config.ml +++ b/src/client/config.ml @@ -6,6 +6,7 @@ type t = { headers: (string * string) list; batch_traces: int option; batch_metrics: int option; + batch_logs: int option; batch_timeout_ms: int; thread: bool; ticker_thread: bool; @@ -21,6 +22,7 @@ let pp out self = headers; batch_traces; batch_metrics; + batch_logs; batch_timeout_ms; thread; ticker_thread; @@ -29,13 +31,13 @@ let pp out self = in Format.fprintf out "{@[ debug=%B;@ url=%S;@ headers=%a;@ batch_traces=%a;@ batch_metrics=%a;@ \ - batch_timeout_ms=%d; thread=%B;@ ticker_thread=%B @]}" - debug url ppheaders headers ppiopt batch_traces ppiopt batch_metrics - batch_timeout_ms thread ticker_thread + batch_logs=%a;@ batch_timeout_ms=%d; thread=%B;@ ticker_thread=%B @]}" + debug url ppheaders headers ppiopt batch_traces ppiopt batch_metrics ppiopt + batch_logs batch_timeout_ms thread ticker_thread let make ?(debug = !debug_) ?(url = get_url ()) ?(headers = get_headers ()) - ?(batch_traces = Some 400) ?(batch_metrics = None) ?(batch_timeout_ms = 500) - ?(thread = true) ?(ticker_thread = true) () : t = + ?(batch_traces = Some 400) ?(batch_metrics = None) ?(batch_logs = Some 400) + ?(batch_timeout_ms = 500) ?(thread = true) ?(ticker_thread = true) () : t = { debug; url; @@ -43,6 +45,7 @@ let make ?(debug = !debug_) ?(url = get_url ()) ?(headers = get_headers ()) batch_traces; batch_metrics; batch_timeout_ms; + batch_logs; thread; ticker_thread; } diff --git a/src/client/config.mli b/src/client/config.mli index adfaab74..3e7cf0bb 100644 --- a/src/client/config.mli +++ b/src/client/config.mli @@ -20,6 +20,9 @@ type t = { Note that traces and metrics are batched separately. Default [None]. *) + batch_logs: int option; + (** Batch logs? See {!batch_metrics} for details. + Default [Some 400] *) batch_timeout_ms: int; (** Number of milliseconds after which we will emit a batch, even incomplete. @@ -39,6 +42,7 @@ val make : ?headers:(string * string) list -> ?batch_traces:int option -> ?batch_metrics:int option -> + ?batch_logs:int option -> ?batch_timeout_ms:int -> ?thread:bool -> ?ticker_thread:bool -> diff --git a/src/client/opentelemetry_client_ocurl.ml b/src/client/opentelemetry_client_ocurl.ml index 0374f328..c69c4245 100644 --- a/src/client/opentelemetry_client_ocurl.ml +++ b/src/client/opentelemetry_client_ocurl.ml @@ -143,6 +143,8 @@ module type EMITTER = sig val push_metrics : Metrics.resource_metrics list -> unit + val push_logs : Logs.resource_logs list -> unit + val set_on_tick_callbacks : (unit -> unit) list ref -> unit val tick : unit -> unit @@ -231,6 +233,9 @@ let mk_emitter ~(config : Config.t) () : (module EMITTER) = = mk_push ?batch:config.batch_metrics () in + let ((module E_logs) : Logs.resource_logs list push), on_logs_full = + mk_push ?batch:config.batch_logs () + in let encoder = Pbrt.Encoder.create () in @@ -239,17 +244,11 @@ let mk_emitter ~(config : Config.t) () : (module EMITTER) = let on_tick_cbs_ = ref (ref []) in let set_on_tick_callbacks = ( := ) on_tick_cbs_ in - let send_metrics_http (l : Metrics.resource_metrics list list) = + let send_http_ ~path ~encode x : unit = Pbrt.Encoder.reset encoder; - let resource_metrics = - List.fold_left (fun acc l -> List.rev_append l acc) [] l - in - Metrics_service.encode_export_metrics_service_request - (Metrics_service.default_export_metrics_service_request ~resource_metrics - ()) - encoder; + encode x encoder; let data = Pbrt.Encoder.to_string encoder in - match C.send ~path:"/v1/metrics" ~decode:(fun _ -> ()) data with + match C.send ~path ~decode:(fun _ -> ()) data with | Ok () -> () | Error err -> (* TODO: log error _via_ otel? *) @@ -257,24 +256,32 @@ let mk_emitter ~(config : Config.t) () : (module EMITTER) = report_err_ err in - let send_traces_http (l : Trace.resource_spans list list) = - Pbrt.Encoder.reset encoder; - let resource_spans = - List.fold_left (fun acc l -> List.rev_append l acc) [] l + let send_metrics_http (l : Metrics.resource_metrics list list) = + let l = List.fold_left (fun acc l -> List.rev_append l acc) [] l in + let x = + Metrics_service.default_export_metrics_service_request ~resource_metrics:l + () in - Trace_service.encode_export_trace_service_request - (Trace_service.default_export_trace_service_request ~resource_spans ()) - encoder; - match - C.send ~path:"/v1/traces" - ~decode:(fun _ -> ()) - (Pbrt.Encoder.to_string encoder) - with - | Ok () -> () - | Error err -> - (* TODO: log error _via_ otel? *) - Atomic.incr n_errors; - report_err_ err + send_http_ ~path:"/v1/metrics" + ~encode:Metrics_service.encode_export_metrics_service_request x + in + + let send_traces_http (l : Trace.resource_spans list list) = + let l = List.fold_left (fun acc l -> List.rev_append l acc) [] l in + let x = + Trace_service.default_export_trace_service_request ~resource_spans:l () + in + send_http_ ~path:"/v1/traces" + ~encode:Trace_service.encode_export_trace_service_request x + in + + let send_logs_http (l : Logs.resource_logs list list) = + let l = List.fold_left (fun acc l -> List.rev_append l acc) [] l in + let x = + Logs_service.default_export_logs_service_request ~resource_logs:l () + in + send_http_ ~path:"/v1/logs" + ~encode:Logs_service.encode_export_logs_service_request x in let last_wakeup = Atomic.make (Mtime_clock.now ()) in @@ -310,6 +317,19 @@ let mk_emitter ~(config : Config.t) () : (module EMITTER) = ) else false in + let emit_logs ?(force = false) () : bool = + if force || ((not force) && E_logs.is_big_enough ()) then ( + let batch = ref [] in + E_logs.pop_iter_all (fun l -> batch := l :: !batch); + let do_something = not (l_is_empty !batch) in + if do_something then ( + send_logs_http !batch; + Atomic.set last_wakeup (Mtime_clock.now ()) + ); + do_something + ) else + false + in let[@inline] guard f = try f () @@ -319,8 +339,8 @@ let mk_emitter ~(config : Config.t) () : (module EMITTER) = in let emit_all_force () = - let@ () = guard in ignore (emit_traces ~force:true () : bool); + ignore (emit_logs ~force:true () : bool); ignore (emit_metrics ~force:true () : bool) in @@ -343,7 +363,8 @@ let mk_emitter ~(config : Config.t) () : (module EMITTER) = let do_metrics = emit_metrics ~force:timeout () in let do_traces = emit_traces ~force:timeout () in - if (not do_metrics) && not do_traces then + let do_logs = emit_logs ~force:timeout () in + if (not do_metrics) && (not do_traces) && not do_logs then (* wait *) let@ () = with_mutex_ m in Condition.wait cond m @@ -352,6 +373,7 @@ let mk_emitter ~(config : Config.t) () : (module EMITTER) = let@ () = guard in ignore (emit_traces ~force:true () : bool); ignore (emit_metrics ~force:true () : bool); + ignore (emit_logs ~force:true () : bool); C.cleanup () in start_bg_thread bg_thread; @@ -398,6 +420,10 @@ let mk_emitter ~(config : Config.t) () : (module EMITTER) = E_metrics.push e; if batch_timeout () then wakeup () + let push_logs e = + E_logs.push e; + if batch_timeout () then wakeup () + let set_on_tick_callbacks = set_on_tick_callbacks let tick = tick @@ -412,6 +438,7 @@ let mk_emitter ~(config : Config.t) () : (module EMITTER) = if Atomic.get needs_gc_metrics then sample_gc_metrics (); ignore (emit_metrics () : bool)); on_trace_full (fun () -> ignore (emit_traces () : bool)); + on_logs_full (fun () -> ignore (emit_logs () : bool)); let cleanup () = emit_all_force (); @@ -429,6 +456,11 @@ let mk_emitter ~(config : Config.t) () : (module EMITTER) = E_metrics.push e; if batch_timeout () then emit_all_force () + let push_logs e = + let@ () = guard in + E_logs.push e; + if batch_timeout () then emit_all_force () + let set_on_tick_callbacks = set_on_tick_callbacks let tick () = @@ -515,6 +547,19 @@ end) push_metrics m; ret ()); } + + let send_logs : Logs.resource_logs list sender = + { + send = + (fun m ~ret -> + let@ () = Lock.with_lock in + if !debug_ then + Format.eprintf "send logs %a@." + (Format.pp_print_list Logs.pp_resource_logs) + m; + push_logs m; + ret ()); + } end let setup_ ~(config : Config.t) () = diff --git a/src/dune b/src/dune index 62680ee0..aef121fa 100644 --- a/src/dune +++ b/src/dune @@ -70,6 +70,19 @@ (run ocaml-protoc %{file} -I %{project_root}/vendor/opentelemetry-proto/ -ml_out . -pp -binary))) +(rule + (alias lint) + (mode promote) + (targets logs_types.ml logs_types.mli logs_pb.ml logs_pb.mli logs_pp.ml + logs_pp.mli) + (deps + (:file + %{project_root}/vendor/opentelemetry-proto/opentelemetry/proto/logs/v1/logs.proto) + (source_tree %{project_root}/vendor/opentelemetry-proto/)) + (action + (run ocaml-protoc %{file} -I %{project_root}/vendor/opentelemetry-proto/ + -ml_out . -pp -binary))) + (rule (alias lint) (mode promote) @@ -96,3 +109,16 @@ (action (run ocaml-protoc %{file} -I %{project_root}/vendor/opentelemetry-proto/ -ml_out . -pp -binary))) + +(rule + (alias lint) + (mode promote) + (targets logs_service_types.ml logs_service_types.mli logs_service_pp.ml + logs_service_pp.mli logs_service_pb.ml logs_service_pb.mli) + (deps + (:file + %{project_root}/vendor/opentelemetry-proto/opentelemetry/proto/collector/logs/v1/logs_service.proto) + (source_tree %{project_root}/vendor/opentelemetry-proto/)) + (action + (run ocaml-protoc %{file} -I %{project_root}/vendor/opentelemetry-proto/ + -ml_out . -pp -binary))) diff --git a/src/logs_pb.ml b/src/logs_pb.ml new file mode 100644 index 00000000..3ec4685a --- /dev/null +++ b/src/logs_pb.ml @@ -0,0 +1,358 @@ +[@@@ocaml.warning "-27-30-39"] + +type log_record_mutable = { + mutable time_unix_nano : int64; + mutable observed_time_unix_nano : int64; + mutable severity_number : Logs_types.severity_number; + mutable severity_text : string; + mutable name : string; + mutable body : Common_types.any_value option; + mutable attributes : Common_types.key_value list; + mutable dropped_attributes_count : int32; + mutable flags : int32; + mutable trace_id : bytes; + mutable span_id : bytes; +} + +let default_log_record_mutable () : log_record_mutable = { + time_unix_nano = 0L; + observed_time_unix_nano = 0L; + severity_number = Logs_types.default_severity_number (); + severity_text = ""; + name = ""; + body = None; + attributes = []; + dropped_attributes_count = 0l; + flags = 0l; + trace_id = Bytes.create 0; + span_id = Bytes.create 0; +} + +type instrumentation_library_logs_mutable = { + mutable instrumentation_library : Common_types.instrumentation_library option; + mutable log_records : Logs_types.log_record list; + mutable schema_url : string; +} + +let default_instrumentation_library_logs_mutable () : instrumentation_library_logs_mutable = { + instrumentation_library = None; + log_records = []; + schema_url = ""; +} + +type resource_logs_mutable = { + mutable resource : Resource_types.resource option; + mutable instrumentation_library_logs : Logs_types.instrumentation_library_logs list; + mutable schema_url : string; +} + +let default_resource_logs_mutable () : resource_logs_mutable = { + resource = None; + instrumentation_library_logs = []; + schema_url = ""; +} + +type logs_data_mutable = { + mutable resource_logs : Logs_types.resource_logs list; +} + +let default_logs_data_mutable () : logs_data_mutable = { + resource_logs = []; +} + + +let rec decode_severity_number d = + match Pbrt.Decoder.int_as_varint d with + | 0 -> (Logs_types.Severity_number_unspecified:Logs_types.severity_number) + | 1 -> (Logs_types.Severity_number_trace:Logs_types.severity_number) + | 2 -> (Logs_types.Severity_number_trace2:Logs_types.severity_number) + | 3 -> (Logs_types.Severity_number_trace3:Logs_types.severity_number) + | 4 -> (Logs_types.Severity_number_trace4:Logs_types.severity_number) + | 5 -> (Logs_types.Severity_number_debug:Logs_types.severity_number) + | 6 -> (Logs_types.Severity_number_debug2:Logs_types.severity_number) + | 7 -> (Logs_types.Severity_number_debug3:Logs_types.severity_number) + | 8 -> (Logs_types.Severity_number_debug4:Logs_types.severity_number) + | 9 -> (Logs_types.Severity_number_info:Logs_types.severity_number) + | 10 -> (Logs_types.Severity_number_info2:Logs_types.severity_number) + | 11 -> (Logs_types.Severity_number_info3:Logs_types.severity_number) + | 12 -> (Logs_types.Severity_number_info4:Logs_types.severity_number) + | 13 -> (Logs_types.Severity_number_warn:Logs_types.severity_number) + | 14 -> (Logs_types.Severity_number_warn2:Logs_types.severity_number) + | 15 -> (Logs_types.Severity_number_warn3:Logs_types.severity_number) + | 16 -> (Logs_types.Severity_number_warn4:Logs_types.severity_number) + | 17 -> (Logs_types.Severity_number_error:Logs_types.severity_number) + | 18 -> (Logs_types.Severity_number_error2:Logs_types.severity_number) + | 19 -> (Logs_types.Severity_number_error3:Logs_types.severity_number) + | 20 -> (Logs_types.Severity_number_error4:Logs_types.severity_number) + | 21 -> (Logs_types.Severity_number_fatal:Logs_types.severity_number) + | 22 -> (Logs_types.Severity_number_fatal2:Logs_types.severity_number) + | 23 -> (Logs_types.Severity_number_fatal3:Logs_types.severity_number) + | 24 -> (Logs_types.Severity_number_fatal4:Logs_types.severity_number) + | _ -> Pbrt.Decoder.malformed_variant "severity_number" + +let rec decode_log_record d = + let v = default_log_record_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + v.attributes <- List.rev v.attributes; + ); continue__ := false + | Some (1, Pbrt.Bits64) -> begin + v.time_unix_nano <- Pbrt.Decoder.int64_as_bits64 d; + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(log_record), field(1)" pk + | Some (11, Pbrt.Bits64) -> begin + v.observed_time_unix_nano <- Pbrt.Decoder.int64_as_bits64 d; + end + | Some (11, pk) -> + Pbrt.Decoder.unexpected_payload "Message(log_record), field(11)" pk + | Some (2, Pbrt.Varint) -> begin + v.severity_number <- decode_severity_number d; + end + | Some (2, pk) -> + Pbrt.Decoder.unexpected_payload "Message(log_record), field(2)" pk + | Some (3, Pbrt.Bytes) -> begin + v.severity_text <- Pbrt.Decoder.string d; + end + | Some (3, pk) -> + Pbrt.Decoder.unexpected_payload "Message(log_record), field(3)" pk + | Some (4, Pbrt.Bytes) -> begin + v.name <- Pbrt.Decoder.string d; + end + | Some (4, pk) -> + Pbrt.Decoder.unexpected_payload "Message(log_record), field(4)" pk + | Some (5, Pbrt.Bytes) -> begin + v.body <- Some (Common_pb.decode_any_value (Pbrt.Decoder.nested d)); + end + | Some (5, pk) -> + Pbrt.Decoder.unexpected_payload "Message(log_record), field(5)" pk + | Some (6, Pbrt.Bytes) -> begin + v.attributes <- (Common_pb.decode_key_value (Pbrt.Decoder.nested d)) :: v.attributes; + end + | Some (6, pk) -> + Pbrt.Decoder.unexpected_payload "Message(log_record), field(6)" pk + | Some (7, Pbrt.Varint) -> begin + v.dropped_attributes_count <- Pbrt.Decoder.int32_as_varint d; + end + | Some (7, pk) -> + Pbrt.Decoder.unexpected_payload "Message(log_record), field(7)" pk + | Some (8, Pbrt.Bits32) -> begin + v.flags <- Pbrt.Decoder.int32_as_bits32 d; + end + | Some (8, pk) -> + Pbrt.Decoder.unexpected_payload "Message(log_record), field(8)" pk + | Some (9, Pbrt.Bytes) -> begin + v.trace_id <- Pbrt.Decoder.bytes d; + end + | Some (9, pk) -> + Pbrt.Decoder.unexpected_payload "Message(log_record), field(9)" pk + | Some (10, Pbrt.Bytes) -> begin + v.span_id <- Pbrt.Decoder.bytes d; + end + | Some (10, pk) -> + Pbrt.Decoder.unexpected_payload "Message(log_record), field(10)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + Logs_types.time_unix_nano = v.time_unix_nano; + Logs_types.observed_time_unix_nano = v.observed_time_unix_nano; + Logs_types.severity_number = v.severity_number; + Logs_types.severity_text = v.severity_text; + Logs_types.name = v.name; + Logs_types.body = v.body; + Logs_types.attributes = v.attributes; + Logs_types.dropped_attributes_count = v.dropped_attributes_count; + Logs_types.flags = v.flags; + Logs_types.trace_id = v.trace_id; + Logs_types.span_id = v.span_id; + } : Logs_types.log_record) + +let rec decode_instrumentation_library_logs d = + let v = default_instrumentation_library_logs_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + v.log_records <- List.rev v.log_records; + ); continue__ := false + | Some (1, Pbrt.Bytes) -> begin + v.instrumentation_library <- Some (Common_pb.decode_instrumentation_library (Pbrt.Decoder.nested d)); + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(instrumentation_library_logs), field(1)" pk + | Some (2, Pbrt.Bytes) -> begin + v.log_records <- (decode_log_record (Pbrt.Decoder.nested d)) :: v.log_records; + end + | Some (2, pk) -> + Pbrt.Decoder.unexpected_payload "Message(instrumentation_library_logs), field(2)" pk + | Some (3, Pbrt.Bytes) -> begin + v.schema_url <- Pbrt.Decoder.string d; + end + | Some (3, pk) -> + Pbrt.Decoder.unexpected_payload "Message(instrumentation_library_logs), field(3)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + Logs_types.instrumentation_library = v.instrumentation_library; + Logs_types.log_records = v.log_records; + Logs_types.schema_url = v.schema_url; + } : Logs_types.instrumentation_library_logs) + +let rec decode_resource_logs d = + let v = default_resource_logs_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + v.instrumentation_library_logs <- List.rev v.instrumentation_library_logs; + ); continue__ := false + | Some (1, Pbrt.Bytes) -> begin + v.resource <- Some (Resource_pb.decode_resource (Pbrt.Decoder.nested d)); + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(resource_logs), field(1)" pk + | Some (2, Pbrt.Bytes) -> begin + v.instrumentation_library_logs <- (decode_instrumentation_library_logs (Pbrt.Decoder.nested d)) :: v.instrumentation_library_logs; + end + | Some (2, pk) -> + Pbrt.Decoder.unexpected_payload "Message(resource_logs), field(2)" pk + | Some (3, Pbrt.Bytes) -> begin + v.schema_url <- Pbrt.Decoder.string d; + end + | Some (3, pk) -> + Pbrt.Decoder.unexpected_payload "Message(resource_logs), field(3)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + Logs_types.resource = v.resource; + Logs_types.instrumentation_library_logs = v.instrumentation_library_logs; + Logs_types.schema_url = v.schema_url; + } : Logs_types.resource_logs) + +let rec decode_logs_data d = + let v = default_logs_data_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + v.resource_logs <- List.rev v.resource_logs; + ); continue__ := false + | Some (1, Pbrt.Bytes) -> begin + v.resource_logs <- (decode_resource_logs (Pbrt.Decoder.nested d)) :: v.resource_logs; + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(logs_data), field(1)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + Logs_types.resource_logs = v.resource_logs; + } : Logs_types.logs_data) + +let rec decode_log_record_flags d = + match Pbrt.Decoder.int_as_varint d with + | 0 -> (Logs_types.Log_record_flag_unspecified:Logs_types.log_record_flags) + | 255 -> (Logs_types.Log_record_flag_trace_flags_mask:Logs_types.log_record_flags) + | _ -> Pbrt.Decoder.malformed_variant "log_record_flags" + +let rec encode_severity_number (v:Logs_types.severity_number) encoder = + match v with + | Logs_types.Severity_number_unspecified -> Pbrt.Encoder.int_as_varint (0) encoder + | Logs_types.Severity_number_trace -> Pbrt.Encoder.int_as_varint 1 encoder + | Logs_types.Severity_number_trace2 -> Pbrt.Encoder.int_as_varint 2 encoder + | Logs_types.Severity_number_trace3 -> Pbrt.Encoder.int_as_varint 3 encoder + | Logs_types.Severity_number_trace4 -> Pbrt.Encoder.int_as_varint 4 encoder + | Logs_types.Severity_number_debug -> Pbrt.Encoder.int_as_varint 5 encoder + | Logs_types.Severity_number_debug2 -> Pbrt.Encoder.int_as_varint 6 encoder + | Logs_types.Severity_number_debug3 -> Pbrt.Encoder.int_as_varint 7 encoder + | Logs_types.Severity_number_debug4 -> Pbrt.Encoder.int_as_varint 8 encoder + | Logs_types.Severity_number_info -> Pbrt.Encoder.int_as_varint 9 encoder + | Logs_types.Severity_number_info2 -> Pbrt.Encoder.int_as_varint 10 encoder + | Logs_types.Severity_number_info3 -> Pbrt.Encoder.int_as_varint 11 encoder + | Logs_types.Severity_number_info4 -> Pbrt.Encoder.int_as_varint 12 encoder + | Logs_types.Severity_number_warn -> Pbrt.Encoder.int_as_varint 13 encoder + | Logs_types.Severity_number_warn2 -> Pbrt.Encoder.int_as_varint 14 encoder + | Logs_types.Severity_number_warn3 -> Pbrt.Encoder.int_as_varint 15 encoder + | Logs_types.Severity_number_warn4 -> Pbrt.Encoder.int_as_varint 16 encoder + | Logs_types.Severity_number_error -> Pbrt.Encoder.int_as_varint 17 encoder + | Logs_types.Severity_number_error2 -> Pbrt.Encoder.int_as_varint 18 encoder + | Logs_types.Severity_number_error3 -> Pbrt.Encoder.int_as_varint 19 encoder + | Logs_types.Severity_number_error4 -> Pbrt.Encoder.int_as_varint 20 encoder + | Logs_types.Severity_number_fatal -> Pbrt.Encoder.int_as_varint 21 encoder + | Logs_types.Severity_number_fatal2 -> Pbrt.Encoder.int_as_varint 22 encoder + | Logs_types.Severity_number_fatal3 -> Pbrt.Encoder.int_as_varint 23 encoder + | Logs_types.Severity_number_fatal4 -> Pbrt.Encoder.int_as_varint 24 encoder + +let rec encode_log_record (v:Logs_types.log_record) encoder = + Pbrt.Encoder.key (1, Pbrt.Bits64) encoder; + Pbrt.Encoder.int64_as_bits64 v.Logs_types.time_unix_nano encoder; + Pbrt.Encoder.key (11, Pbrt.Bits64) encoder; + Pbrt.Encoder.int64_as_bits64 v.Logs_types.observed_time_unix_nano encoder; + Pbrt.Encoder.key (2, Pbrt.Varint) encoder; + encode_severity_number v.Logs_types.severity_number encoder; + Pbrt.Encoder.key (3, Pbrt.Bytes) encoder; + Pbrt.Encoder.string v.Logs_types.severity_text encoder; + Pbrt.Encoder.key (4, Pbrt.Bytes) encoder; + Pbrt.Encoder.string v.Logs_types.name encoder; + begin match v.Logs_types.body with + | Some x -> + Pbrt.Encoder.key (5, Pbrt.Bytes) encoder; + Pbrt.Encoder.nested (Common_pb.encode_any_value x) encoder; + | None -> (); + end; + List.iter (fun x -> + Pbrt.Encoder.key (6, Pbrt.Bytes) encoder; + Pbrt.Encoder.nested (Common_pb.encode_key_value x) encoder; + ) v.Logs_types.attributes; + Pbrt.Encoder.key (7, Pbrt.Varint) encoder; + Pbrt.Encoder.int32_as_varint v.Logs_types.dropped_attributes_count encoder; + Pbrt.Encoder.key (8, Pbrt.Bits32) encoder; + Pbrt.Encoder.int32_as_bits32 v.Logs_types.flags encoder; + Pbrt.Encoder.key (9, Pbrt.Bytes) encoder; + Pbrt.Encoder.bytes v.Logs_types.trace_id encoder; + Pbrt.Encoder.key (10, Pbrt.Bytes) encoder; + Pbrt.Encoder.bytes v.Logs_types.span_id encoder; + () + +let rec encode_instrumentation_library_logs (v:Logs_types.instrumentation_library_logs) encoder = + begin match v.Logs_types.instrumentation_library with + | Some x -> + Pbrt.Encoder.key (1, Pbrt.Bytes) encoder; + Pbrt.Encoder.nested (Common_pb.encode_instrumentation_library x) encoder; + | None -> (); + end; + List.iter (fun x -> + Pbrt.Encoder.key (2, Pbrt.Bytes) encoder; + Pbrt.Encoder.nested (encode_log_record x) encoder; + ) v.Logs_types.log_records; + Pbrt.Encoder.key (3, Pbrt.Bytes) encoder; + Pbrt.Encoder.string v.Logs_types.schema_url encoder; + () + +let rec encode_resource_logs (v:Logs_types.resource_logs) encoder = + begin match v.Logs_types.resource with + | Some x -> + Pbrt.Encoder.key (1, Pbrt.Bytes) encoder; + Pbrt.Encoder.nested (Resource_pb.encode_resource x) encoder; + | None -> (); + end; + List.iter (fun x -> + Pbrt.Encoder.key (2, Pbrt.Bytes) encoder; + Pbrt.Encoder.nested (encode_instrumentation_library_logs x) encoder; + ) v.Logs_types.instrumentation_library_logs; + Pbrt.Encoder.key (3, Pbrt.Bytes) encoder; + Pbrt.Encoder.string v.Logs_types.schema_url encoder; + () + +let rec encode_logs_data (v:Logs_types.logs_data) encoder = + List.iter (fun x -> + Pbrt.Encoder.key (1, Pbrt.Bytes) encoder; + Pbrt.Encoder.nested (encode_resource_logs x) encoder; + ) v.Logs_types.resource_logs; + () + +let rec encode_log_record_flags (v:Logs_types.log_record_flags) encoder = + match v with + | Logs_types.Log_record_flag_unspecified -> Pbrt.Encoder.int_as_varint (0) encoder + | Logs_types.Log_record_flag_trace_flags_mask -> Pbrt.Encoder.int_as_varint 255 encoder diff --git a/src/logs_pb.mli b/src/logs_pb.mli new file mode 100644 index 00000000..c91527be --- /dev/null +++ b/src/logs_pb.mli @@ -0,0 +1,43 @@ +(** logs.proto Binary Encoding *) + + +(** {2 Protobuf Encoding} *) + +val encode_severity_number : Logs_types.severity_number -> Pbrt.Encoder.t -> unit +(** [encode_severity_number v encoder] encodes [v] with the given [encoder] *) + +val encode_log_record : Logs_types.log_record -> Pbrt.Encoder.t -> unit +(** [encode_log_record v encoder] encodes [v] with the given [encoder] *) + +val encode_instrumentation_library_logs : Logs_types.instrumentation_library_logs -> Pbrt.Encoder.t -> unit +(** [encode_instrumentation_library_logs v encoder] encodes [v] with the given [encoder] *) + +val encode_resource_logs : Logs_types.resource_logs -> Pbrt.Encoder.t -> unit +(** [encode_resource_logs v encoder] encodes [v] with the given [encoder] *) + +val encode_logs_data : Logs_types.logs_data -> Pbrt.Encoder.t -> unit +(** [encode_logs_data v encoder] encodes [v] with the given [encoder] *) + +val encode_log_record_flags : Logs_types.log_record_flags -> Pbrt.Encoder.t -> unit +(** [encode_log_record_flags v encoder] encodes [v] with the given [encoder] *) + + +(** {2 Protobuf Decoding} *) + +val decode_severity_number : Pbrt.Decoder.t -> Logs_types.severity_number +(** [decode_severity_number decoder] decodes a [severity_number] value from [decoder] *) + +val decode_log_record : Pbrt.Decoder.t -> Logs_types.log_record +(** [decode_log_record decoder] decodes a [log_record] value from [decoder] *) + +val decode_instrumentation_library_logs : Pbrt.Decoder.t -> Logs_types.instrumentation_library_logs +(** [decode_instrumentation_library_logs decoder] decodes a [instrumentation_library_logs] value from [decoder] *) + +val decode_resource_logs : Pbrt.Decoder.t -> Logs_types.resource_logs +(** [decode_resource_logs decoder] decodes a [resource_logs] value from [decoder] *) + +val decode_logs_data : Pbrt.Decoder.t -> Logs_types.logs_data +(** [decode_logs_data decoder] decodes a [logs_data] value from [decoder] *) + +val decode_log_record_flags : Pbrt.Decoder.t -> Logs_types.log_record_flags +(** [decode_log_record_flags decoder] decodes a [log_record_flags] value from [decoder] *) diff --git a/src/logs_pp.ml b/src/logs_pp.ml new file mode 100644 index 00000000..2e5e70e2 --- /dev/null +++ b/src/logs_pp.ml @@ -0,0 +1,72 @@ +[@@@ocaml.warning "-27-30-39"] + +let rec pp_severity_number fmt (v:Logs_types.severity_number) = + match v with + | Logs_types.Severity_number_unspecified -> Format.fprintf fmt "Severity_number_unspecified" + | Logs_types.Severity_number_trace -> Format.fprintf fmt "Severity_number_trace" + | Logs_types.Severity_number_trace2 -> Format.fprintf fmt "Severity_number_trace2" + | Logs_types.Severity_number_trace3 -> Format.fprintf fmt "Severity_number_trace3" + | Logs_types.Severity_number_trace4 -> Format.fprintf fmt "Severity_number_trace4" + | Logs_types.Severity_number_debug -> Format.fprintf fmt "Severity_number_debug" + | Logs_types.Severity_number_debug2 -> Format.fprintf fmt "Severity_number_debug2" + | Logs_types.Severity_number_debug3 -> Format.fprintf fmt "Severity_number_debug3" + | Logs_types.Severity_number_debug4 -> Format.fprintf fmt "Severity_number_debug4" + | Logs_types.Severity_number_info -> Format.fprintf fmt "Severity_number_info" + | Logs_types.Severity_number_info2 -> Format.fprintf fmt "Severity_number_info2" + | Logs_types.Severity_number_info3 -> Format.fprintf fmt "Severity_number_info3" + | Logs_types.Severity_number_info4 -> Format.fprintf fmt "Severity_number_info4" + | Logs_types.Severity_number_warn -> Format.fprintf fmt "Severity_number_warn" + | Logs_types.Severity_number_warn2 -> Format.fprintf fmt "Severity_number_warn2" + | Logs_types.Severity_number_warn3 -> Format.fprintf fmt "Severity_number_warn3" + | Logs_types.Severity_number_warn4 -> Format.fprintf fmt "Severity_number_warn4" + | Logs_types.Severity_number_error -> Format.fprintf fmt "Severity_number_error" + | Logs_types.Severity_number_error2 -> Format.fprintf fmt "Severity_number_error2" + | Logs_types.Severity_number_error3 -> Format.fprintf fmt "Severity_number_error3" + | Logs_types.Severity_number_error4 -> Format.fprintf fmt "Severity_number_error4" + | Logs_types.Severity_number_fatal -> Format.fprintf fmt "Severity_number_fatal" + | Logs_types.Severity_number_fatal2 -> Format.fprintf fmt "Severity_number_fatal2" + | Logs_types.Severity_number_fatal3 -> Format.fprintf fmt "Severity_number_fatal3" + | Logs_types.Severity_number_fatal4 -> Format.fprintf fmt "Severity_number_fatal4" + +let rec pp_log_record fmt (v:Logs_types.log_record) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "time_unix_nano" Pbrt.Pp.pp_int64 fmt v.Logs_types.time_unix_nano; + Pbrt.Pp.pp_record_field ~first:false "observed_time_unix_nano" Pbrt.Pp.pp_int64 fmt v.Logs_types.observed_time_unix_nano; + Pbrt.Pp.pp_record_field ~first:false "severity_number" pp_severity_number fmt v.Logs_types.severity_number; + Pbrt.Pp.pp_record_field ~first:false "severity_text" Pbrt.Pp.pp_string fmt v.Logs_types.severity_text; + Pbrt.Pp.pp_record_field ~first:false "name" Pbrt.Pp.pp_string fmt v.Logs_types.name; + Pbrt.Pp.pp_record_field ~first:false "body" (Pbrt.Pp.pp_option Common_pp.pp_any_value) fmt v.Logs_types.body; + Pbrt.Pp.pp_record_field ~first:false "attributes" (Pbrt.Pp.pp_list Common_pp.pp_key_value) fmt v.Logs_types.attributes; + Pbrt.Pp.pp_record_field ~first:false "dropped_attributes_count" Pbrt.Pp.pp_int32 fmt v.Logs_types.dropped_attributes_count; + Pbrt.Pp.pp_record_field ~first:false "flags" Pbrt.Pp.pp_int32 fmt v.Logs_types.flags; + Pbrt.Pp.pp_record_field ~first:false "trace_id" Pbrt.Pp.pp_bytes fmt v.Logs_types.trace_id; + Pbrt.Pp.pp_record_field ~first:false "span_id" Pbrt.Pp.pp_bytes fmt v.Logs_types.span_id; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_instrumentation_library_logs fmt (v:Logs_types.instrumentation_library_logs) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "instrumentation_library" (Pbrt.Pp.pp_option Common_pp.pp_instrumentation_library) fmt v.Logs_types.instrumentation_library; + Pbrt.Pp.pp_record_field ~first:false "log_records" (Pbrt.Pp.pp_list pp_log_record) fmt v.Logs_types.log_records; + Pbrt.Pp.pp_record_field ~first:false "schema_url" Pbrt.Pp.pp_string fmt v.Logs_types.schema_url; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_resource_logs fmt (v:Logs_types.resource_logs) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "resource" (Pbrt.Pp.pp_option Resource_pp.pp_resource) fmt v.Logs_types.resource; + Pbrt.Pp.pp_record_field ~first:false "instrumentation_library_logs" (Pbrt.Pp.pp_list pp_instrumentation_library_logs) fmt v.Logs_types.instrumentation_library_logs; + Pbrt.Pp.pp_record_field ~first:false "schema_url" Pbrt.Pp.pp_string fmt v.Logs_types.schema_url; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_logs_data fmt (v:Logs_types.logs_data) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "resource_logs" (Pbrt.Pp.pp_list pp_resource_logs) fmt v.Logs_types.resource_logs; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_log_record_flags fmt (v:Logs_types.log_record_flags) = + match v with + | Logs_types.Log_record_flag_unspecified -> Format.fprintf fmt "Log_record_flag_unspecified" + | Logs_types.Log_record_flag_trace_flags_mask -> Format.fprintf fmt "Log_record_flag_trace_flags_mask" diff --git a/src/logs_pp.mli b/src/logs_pp.mli new file mode 100644 index 00000000..0ebaa575 --- /dev/null +++ b/src/logs_pp.mli @@ -0,0 +1,22 @@ +(** logs.proto Pretty Printing *) + + +(** {2 Formatters} *) + +val pp_severity_number : Format.formatter -> Logs_types.severity_number -> unit +(** [pp_severity_number v] formats v *) + +val pp_log_record : Format.formatter -> Logs_types.log_record -> unit +(** [pp_log_record v] formats v *) + +val pp_instrumentation_library_logs : Format.formatter -> Logs_types.instrumentation_library_logs -> unit +(** [pp_instrumentation_library_logs v] formats v *) + +val pp_resource_logs : Format.formatter -> Logs_types.resource_logs -> unit +(** [pp_resource_logs v] formats v *) + +val pp_logs_data : Format.formatter -> Logs_types.logs_data -> unit +(** [pp_logs_data v] formats v *) + +val pp_log_record_flags : Format.formatter -> Logs_types.log_record_flags -> unit +(** [pp_log_record_flags v] formats v *) diff --git a/src/logs_service_pb.ml b/src/logs_service_pb.ml new file mode 100644 index 00000000..623d903e --- /dev/null +++ b/src/logs_service_pb.ml @@ -0,0 +1,36 @@ +[@@@ocaml.warning "-27-30-39"] + +type export_logs_service_request_mutable = { + mutable resource_logs : Logs_types.resource_logs list; +} + +let default_export_logs_service_request_mutable () : export_logs_service_request_mutable = { + resource_logs = []; +} + + +let rec decode_export_logs_service_request d = + let v = default_export_logs_service_request_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + v.resource_logs <- List.rev v.resource_logs; + ); continue__ := false + | Some (1, Pbrt.Bytes) -> begin + v.resource_logs <- (Logs_pb.decode_resource_logs (Pbrt.Decoder.nested d)) :: v.resource_logs; + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(export_logs_service_request), field(1)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + Logs_service_types.resource_logs = v.resource_logs; + } : Logs_service_types.export_logs_service_request) + +let rec encode_export_logs_service_request (v:Logs_service_types.export_logs_service_request) encoder = + List.iter (fun x -> + Pbrt.Encoder.key (1, Pbrt.Bytes) encoder; + Pbrt.Encoder.nested (Logs_pb.encode_resource_logs x) encoder; + ) v.Logs_service_types.resource_logs; + () diff --git a/src/logs_service_pb.mli b/src/logs_service_pb.mli new file mode 100644 index 00000000..ce1c2c9a --- /dev/null +++ b/src/logs_service_pb.mli @@ -0,0 +1,13 @@ +(** logs_service.proto Binary Encoding *) + + +(** {2 Protobuf Encoding} *) + +val encode_export_logs_service_request : Logs_service_types.export_logs_service_request -> Pbrt.Encoder.t -> unit +(** [encode_export_logs_service_request v encoder] encodes [v] with the given [encoder] *) + + +(** {2 Protobuf Decoding} *) + +val decode_export_logs_service_request : Pbrt.Decoder.t -> Logs_service_types.export_logs_service_request +(** [decode_export_logs_service_request decoder] decodes a [export_logs_service_request] value from [decoder] *) diff --git a/src/logs_service_pp.ml b/src/logs_service_pp.ml new file mode 100644 index 00000000..1372330e --- /dev/null +++ b/src/logs_service_pp.ml @@ -0,0 +1,7 @@ +[@@@ocaml.warning "-27-30-39"] + +let rec pp_export_logs_service_request fmt (v:Logs_service_types.export_logs_service_request) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "resource_logs" (Pbrt.Pp.pp_list Logs_pp.pp_resource_logs) fmt v.Logs_service_types.resource_logs; + in + Pbrt.Pp.pp_brk pp_i fmt () diff --git a/src/logs_service_pp.mli b/src/logs_service_pp.mli new file mode 100644 index 00000000..d282ea85 --- /dev/null +++ b/src/logs_service_pp.mli @@ -0,0 +1,7 @@ +(** logs_service.proto Pretty Printing *) + + +(** {2 Formatters} *) + +val pp_export_logs_service_request : Format.formatter -> Logs_service_types.export_logs_service_request -> unit +(** [pp_export_logs_service_request v] formats v *) diff --git a/src/logs_service_types.ml b/src/logs_service_types.ml new file mode 100644 index 00000000..36b9a306 --- /dev/null +++ b/src/logs_service_types.ml @@ -0,0 +1,12 @@ +[@@@ocaml.warning "-27-30-39"] + + +type export_logs_service_request = { + resource_logs : Logs_types.resource_logs list; +} + +let rec default_export_logs_service_request + ?resource_logs:((resource_logs:Logs_types.resource_logs list) = []) + () : export_logs_service_request = { + resource_logs; +} diff --git a/src/logs_service_types.mli b/src/logs_service_types.mli new file mode 100644 index 00000000..571d6c7a --- /dev/null +++ b/src/logs_service_types.mli @@ -0,0 +1,18 @@ +(** logs_service.proto Types *) + + + +(** {2 Types} *) + +type export_logs_service_request = { + resource_logs : Logs_types.resource_logs list; +} + + +(** {2 Default values} *) + +val default_export_logs_service_request : + ?resource_logs:Logs_types.resource_logs list -> + unit -> + export_logs_service_request +(** [default_export_logs_service_request ()] is the default value for type [export_logs_service_request] *) diff --git a/src/logs_types.ml b/src/logs_types.ml new file mode 100644 index 00000000..894bf662 --- /dev/null +++ b/src/logs_types.ml @@ -0,0 +1,119 @@ +[@@@ocaml.warning "-27-30-39"] + + +type severity_number = + | Severity_number_unspecified + | Severity_number_trace + | Severity_number_trace2 + | Severity_number_trace3 + | Severity_number_trace4 + | Severity_number_debug + | Severity_number_debug2 + | Severity_number_debug3 + | Severity_number_debug4 + | Severity_number_info + | Severity_number_info2 + | Severity_number_info3 + | Severity_number_info4 + | Severity_number_warn + | Severity_number_warn2 + | Severity_number_warn3 + | Severity_number_warn4 + | Severity_number_error + | Severity_number_error2 + | Severity_number_error3 + | Severity_number_error4 + | Severity_number_fatal + | Severity_number_fatal2 + | Severity_number_fatal3 + | Severity_number_fatal4 + +type log_record = { + time_unix_nano : int64; + observed_time_unix_nano : int64; + severity_number : severity_number; + severity_text : string; + name : string; + body : Common_types.any_value option; + attributes : Common_types.key_value list; + dropped_attributes_count : int32; + flags : int32; + trace_id : bytes; + span_id : bytes; +} + +type instrumentation_library_logs = { + instrumentation_library : Common_types.instrumentation_library option; + log_records : log_record list; + schema_url : string; +} + +type resource_logs = { + resource : Resource_types.resource option; + instrumentation_library_logs : instrumentation_library_logs list; + schema_url : string; +} + +type logs_data = { + resource_logs : resource_logs list; +} + +type log_record_flags = + | Log_record_flag_unspecified + | Log_record_flag_trace_flags_mask + +let rec default_severity_number () = (Severity_number_unspecified:severity_number) + +let rec default_log_record + ?time_unix_nano:((time_unix_nano:int64) = 0L) + ?observed_time_unix_nano:((observed_time_unix_nano:int64) = 0L) + ?severity_number:((severity_number:severity_number) = default_severity_number ()) + ?severity_text:((severity_text:string) = "") + ?name:((name:string) = "") + ?body:((body:Common_types.any_value option) = None) + ?attributes:((attributes:Common_types.key_value list) = []) + ?dropped_attributes_count:((dropped_attributes_count:int32) = 0l) + ?flags:((flags:int32) = 0l) + ?trace_id:((trace_id:bytes) = Bytes.create 0) + ?span_id:((span_id:bytes) = Bytes.create 0) + () : log_record = { + time_unix_nano; + observed_time_unix_nano; + severity_number; + severity_text; + name; + body; + attributes; + dropped_attributes_count; + flags; + trace_id; + span_id; +} + +let rec default_instrumentation_library_logs + ?instrumentation_library:((instrumentation_library:Common_types.instrumentation_library option) = None) + ?log_records:((log_records:log_record list) = []) + ?schema_url:((schema_url:string) = "") + () : instrumentation_library_logs = { + instrumentation_library; + log_records; + schema_url; +} + +let rec default_resource_logs + ?resource:((resource:Resource_types.resource option) = None) + ?instrumentation_library_logs:((instrumentation_library_logs:instrumentation_library_logs list) = []) + ?schema_url:((schema_url:string) = "") + () : resource_logs = { + resource; + instrumentation_library_logs; + schema_url; +} + +let rec default_logs_data + ?resource_logs:((resource_logs:resource_logs list) = []) + () : logs_data = { + resource_logs; +} + +let rec default_log_record_flags () = (Log_record_flag_unspecified:log_record_flags) diff --git a/src/logs_types.mli b/src/logs_types.mli new file mode 100644 index 00000000..2f9694de --- /dev/null +++ b/src/logs_types.mli @@ -0,0 +1,113 @@ +(** logs.proto Types *) + + + +(** {2 Types} *) + +type severity_number = + | Severity_number_unspecified + | Severity_number_trace + | Severity_number_trace2 + | Severity_number_trace3 + | Severity_number_trace4 + | Severity_number_debug + | Severity_number_debug2 + | Severity_number_debug3 + | Severity_number_debug4 + | Severity_number_info + | Severity_number_info2 + | Severity_number_info3 + | Severity_number_info4 + | Severity_number_warn + | Severity_number_warn2 + | Severity_number_warn3 + | Severity_number_warn4 + | Severity_number_error + | Severity_number_error2 + | Severity_number_error3 + | Severity_number_error4 + | Severity_number_fatal + | Severity_number_fatal2 + | Severity_number_fatal3 + | Severity_number_fatal4 + +type log_record = { + time_unix_nano : int64; + observed_time_unix_nano : int64; + severity_number : severity_number; + severity_text : string; + name : string; + body : Common_types.any_value option; + attributes : Common_types.key_value list; + dropped_attributes_count : int32; + flags : int32; + trace_id : bytes; + span_id : bytes; +} + +type instrumentation_library_logs = { + instrumentation_library : Common_types.instrumentation_library option; + log_records : log_record list; + schema_url : string; +} + +type resource_logs = { + resource : Resource_types.resource option; + instrumentation_library_logs : instrumentation_library_logs list; + schema_url : string; +} + +type logs_data = { + resource_logs : resource_logs list; +} + +type log_record_flags = + | Log_record_flag_unspecified + | Log_record_flag_trace_flags_mask + + +(** {2 Default values} *) + +val default_severity_number : unit -> severity_number +(** [default_severity_number ()] is the default value for type [severity_number] *) + +val default_log_record : + ?time_unix_nano:int64 -> + ?observed_time_unix_nano:int64 -> + ?severity_number:severity_number -> + ?severity_text:string -> + ?name:string -> + ?body:Common_types.any_value option -> + ?attributes:Common_types.key_value list -> + ?dropped_attributes_count:int32 -> + ?flags:int32 -> + ?trace_id:bytes -> + ?span_id:bytes -> + unit -> + log_record +(** [default_log_record ()] is the default value for type [log_record] *) + +val default_instrumentation_library_logs : + ?instrumentation_library:Common_types.instrumentation_library option -> + ?log_records:log_record list -> + ?schema_url:string -> + unit -> + instrumentation_library_logs +(** [default_instrumentation_library_logs ()] is the default value for type [instrumentation_library_logs] *) + +val default_resource_logs : + ?resource:Resource_types.resource option -> + ?instrumentation_library_logs:instrumentation_library_logs list -> + ?schema_url:string -> + unit -> + resource_logs +(** [default_resource_logs ()] is the default value for type [resource_logs] *) + +val default_logs_data : + ?resource_logs:resource_logs list -> + unit -> + logs_data +(** [default_logs_data ()] is the default value for type [logs_data] *) + +val default_log_record_flags : unit -> log_record_flags +(** [default_log_record_flags ()] is the default value for type [log_record_flags] *) diff --git a/src/opentelemetry.ml b/src/opentelemetry.ml index df37c8f4..ef335c3d 100644 --- a/src/opentelemetry.ml +++ b/src/opentelemetry.ml @@ -51,6 +51,18 @@ module Proto = struct include Status_pp include Status_pb end + + module Logs = struct + include Logs_types + include Logs_pb + include Logs_pp + end + + module Logs_service = struct + include Logs_service_types + include Logs_service_pb + include Logs_service_pp + end end (** {2 Timestamps} *) @@ -104,6 +116,8 @@ module Collector = struct val send_metrics : Metrics.resource_metrics list sender + val send_logs : Logs.resource_logs list sender + val signal_emit_gc_metrics : unit -> unit (** Signal the backend that it should emit GC metrics when it has the chance. This should be installed in a GC alarm or another form @@ -153,6 +167,11 @@ module Collector = struct | None -> ret () | Some (module B) -> B.send_metrics.send l ~ret + let send_logs (l : Logs.resource_logs list) ~ret = + match !backend with + | None -> ret () + | Some (module B) -> B.send_logs.send l ~ret + let[@inline] rand_bytes_16 () = !Rand_bytes.rand_bytes_16 () let[@inline] rand_bytes_8 () = !Rand_bytes.rand_bytes_8 () @@ -734,10 +753,100 @@ module Metrics = struct Collector.send_metrics [ rm ] ~ret:ignore end -(** A set of callbacks that produce metrics when called. +(** Logs. + See {{: https://opentelemetry.io/docs/reference/specification/overview/#log-signal} the spec} *) +module Logs = struct + open Logs_types + + type t = log_record + + (** Severity level of a log event *) + type severity = Logs_types.severity_number = + | Severity_number_unspecified + | Severity_number_trace + | Severity_number_trace2 + | Severity_number_trace3 + | Severity_number_trace4 + | Severity_number_debug + | Severity_number_debug2 + | Severity_number_debug3 + | Severity_number_debug4 + | Severity_number_info + | Severity_number_info2 + | Severity_number_info3 + | Severity_number_info4 + | Severity_number_warn + | Severity_number_warn2 + | Severity_number_warn3 + | Severity_number_warn4 + | Severity_number_error + | Severity_number_error2 + | Severity_number_error3 + | Severity_number_error4 + | Severity_number_fatal + | Severity_number_fatal2 + | Severity_number_fatal3 + | Severity_number_fatal4 + + let pp_severity = Logs_pp.pp_severity_number + + type flags = Logs_types.log_record_flags = + | Log_record_flag_unspecified + | Log_record_flag_trace_flags_mask + + let pp_flags = Logs_pp.pp_log_record_flags + + (** Make a single log entry *) + let make ?time ?(observed_time_unix_nano = Timestamp_ns.now_unix_ns ()) + ?severity ?log_level ?flags ?trace_id ?span_id (body : value) : t = + let time_unix_nano = + match time with + | None -> observed_time_unix_nano + | Some t -> t + in + let trace_id = Option.map Trace_id.to_bytes trace_id in + let span_id = Option.map Span_id.to_bytes span_id in + let body = _conv_value body in + default_log_record ~time_unix_nano ~observed_time_unix_nano + ?severity_number:severity ?severity_text:log_level ?flags ?trace_id + ?span_id ~body () + + (** Make a log entry whose body is a string *) + let make_str ?time ?observed_time_unix_nano ?severity ?log_level ?flags + ?trace_id ?span_id (body : string) : t = + make ?time ?observed_time_unix_nano ?severity ?log_level ?flags ?trace_id + ?span_id (`String body) + + (** Make a log entry with format *) + let make_strf ?time ?observed_time_unix_nano ?severity ?log_level ?flags + ?trace_id ?span_id fmt = + Format.kasprintf + (fun bod -> + make_str ?time ?observed_time_unix_nano ?severity ?log_level ?flags + ?trace_id ?span_id bod) + fmt + + let emit ?service_name ?attrs (l : t list) : unit = + let attributes = Globals.mk_attributes ?service_name ?attrs () in + let resource = Proto.Resource.default_resource ~attributes () in + let ll = + default_instrumentation_library_logs + ~instrumentation_library:(Some Globals.instrumentation_library) + ~log_records:l () + in + let rl = + default_resource_logs ~resource:(Some resource) + ~instrumentation_library_logs:[ ll ] () + in + Collector.send_logs [ rl ] ~ret:ignore + +end +(** A set of callbacks that produce metrics when called. The metrics are automatically called regularly. + + This allows applications to register metrics callbacks from various points in the program (or even in libraries), and not worry about setting alarms/intervals to emit them. *) @@ -758,8 +867,6 @@ module Metrics_callbacks = struct cbs_ := f :: !cbs_ end -module Logs = struct end - (** {2 Utils} *) (** Implementation of the W3C Trace Context spec diff --git a/tests/bin/emit1.ml b/tests/bin/emit1.ml index e712269c..4ffc4824 100644 --- a/tests/bin/emit1.ml +++ b/tests/bin/emit1.ml @@ -34,6 +34,13 @@ let run () = Unix.sleepf !sleep_outer; incr num_sleep; + T.Logs.( + emit + [ + make_strf ~trace_id:scope.trace_id ~span_id:scope.span_id + ~severity:Severity_number_info "inner at %d" j; + ]); + incr i; try