open Xlog let default_socket_path = "/run/systemd/journal/socket" type t = { mutex : Mutex.t; sock_fd : Eio_unix.Fd.t; buf : Buffer.t; } let add_field dgram key value = if String.contains value '\n' then begin Buffer.add_string dgram key; Buffer.add_char dgram '\n'; Buffer.add_int64_le dgram (Int64.of_int (String.length value)); Buffer.add_string dgram value; Buffer.add_char dgram '\n'; end else Printf.bprintf dgram "%s=%s\n" key value let syslog_priority = function | TRACE | DEBUG -> "7" (* LOG_DEBUG *) | INFO -> "6" (* LOG_INFO *) | WARN -> "4" (* LOG_WARNING *) | ERROR -> "3" (* LOG_ERR *) external unix_code_of_unix_error : Unix.error -> int = "ocaml_systemd_unix_code_of_unix_error" let get_errno errno exn = if errno != 0 then errno else match exn with | Some ((Unix.Unix_error (err, _, _)), _) -> unix_code_of_unix_error err | _ -> 0 let writer t ~ts ~ns ~filename ~lineno ~func ~errno ~exn ~lvl msg = Mutex.lock t.mutex; let dgram = Buffer.clear t.buf; ignore ts; let maybe_exn = match exn with | Some (exn, bt) -> Printf.sprintf "\nException: %s\n%s" (Printexc.to_string exn) (Printexc.raw_backtrace_to_string bt) | None -> "" in add_field t.buf "MESSAGE" (Printf.sprintf "%s: %s%s" ns msg maybe_exn); add_field t.buf "PRIORITY" (syslog_priority lvl); begin if not (filename = "") then add_field t.buf "CODE_FILE" filename; add_field t.buf "CODE_LINE" (Printf.sprintf "%d" lineno) end; begin if not (func = "") then add_field t.buf "CODE_FUNC" func end; let errno = get_errno errno exn in begin if errno != 0 then add_field t.buf "ERRNO" (Printf.sprintf "%d" errno) end; Buffer.to_bytes t.buf in Mutex.unlock t.mutex; let buf = [(Cstruct.of_bytes dgram)] in let sent = Eio_linux.Low_level.send_msg t.sock_fd buf in assert (sent = Cstruct.lenv buf) let make_writer ~sw ~env = if (Eio.Stdenv.backend_id env <> "linux") then failwith "Backend must be Eio_linux"; let sock = Unix.socket ~cloexec:true Unix.PF_UNIX Unix.SOCK_DGRAM 0 in let sock = Eio_unix.Fd.of_unix ~sw ~seekable:false ~close_unix:true sock in (* this path isn't configurable in libsystemd, so i don't see a reason to take an argument for it here *) Eio_linux.Low_level.connect sock (Unix.ADDR_UNIX default_socket_path); writer { mutex = Mutex.create (); sock_fd = sock; buf = Buffer.create 256; }