1234567891011121314151617181920212223242526272829303132333435363738394041openForeignopenCtypesopenCtypes_staticincludeEcho_loglettracefmt=logTracefmtletinfofmt=logInfofmtletwarnfmt=logWarnfmtleterrorfmt=logErrorfmtletfatalfmt=logFatalfmt(* OCaml callback functions *)letecho_trace_cbfmt=trace"[C] %s"fmtletecho_info_cbfmt=info"[C] %s"fmtletecho_warn_cbfmt=warn"[C] %s"fmtletecho_error_cbfmt=error"[C] %s"fmtletecho_fatal_cbfmt=fatal "[C]%s" fmt(* C side callback type *)letecho_cb_type=funptr(string@->returningvoid)letregister=foreign"echo_register"(int@->echo_cb_type @->returningvoid)(* ensures that the C object file is actually linked into the final executable,
even if none of its symbols are directly used from OCaml (eg. if the user just uses ocaml logging).
Without this, the linker might discard the C object file, and the callbacks wouldn't be registered at runtime. *)externalforce_link:unit->unit="_echo_force_link"(* OCaml 5.3 (and earlier) may GC closures passed to C unless retained.
These callbacks must be kept alive to avoid CallToExpiredClosure errors. *)let_callbacks:(int*(string->unit))list=[(0,echo_trace_cb);(1,echo_info_cb);(2,echo_warn_cb);(3,echo_error_cb);(4,echo_fatal_cb);]let()=force_link();List.iter(fun(lvl,cb)->registerlvlcb)_callbacks