dbuenzli / logs

Logging infrastructure for OCaml
http://erratique.ch/software/logs
ISC License
87 stars 19 forks source link

Consider decoupling formatting from output #8

Closed edwintorok closed 8 years ago

edwintorok commented 8 years ago

IIUC the reporter currently has to perform these tasks:

  1. call the user supplied 'a msgf to get the actual message
  2. take into consideration the log level, and tags to perform the final report (message)
  3. actually write the message to a destination

I'd like to be able to change the log destination independently from formatting, e.g. to change between a direct output to a channel, or Lwt write, or syslog, etc.

I wouldn't mind if you add a separate field to type reporter to accomplish this, and another continuation argument to kmsg. The first continuation would be for returning from the report formatter and writer function (currently report field), and the 2nd for signaling completion by the report writing function (the new field proposed here).

Edit: removed comment about composing tag formatting, tags already have their own pretty printers

Note: I don't want to restrict the report writer to strings, so perhaps the report writer should invoke the report formatter with its own Format.formatter (possible printing to a buffer), and once that is finished, write the message in its own way.

dbuenzli commented 8 years ago

Note that it first does 2. and then if the log level is sufficient it does 1.

This is the same request as what you suggest in #5 right ?

edwintorok commented 8 years ago

On 12/28/2015 10:49 AM, Daniel Bünzli wrote:

Note that it first does 2. and then if the log level is sufficient it does 1.

This is the same request as what you suggest in #5 https://github.com/dbuenzli/logs/issues/5 right ?

If you implement this you also get whats needed for the suggestion in #5: in #5 its about adding new continuation kdone here it is both about adding kdone and a new field to the reporter for writing the output (which calls kdone when finished).

dbuenzli commented 8 years ago

Not sure I understand why you want this one then. The reporter as it exists now can simply call kdone.

edwintorok commented 8 years ago

Indeed what I wanted here could be accomplished with a signature like this:

type reporter = {
  report :
    'a 'b.
      Logs.src ->
      Logs.level ->
      (unit -> 'b) -> (unit -> unit) -> ('a, unit) Logs.msgf -> 'b;
}
val lwt_reporter :
  ?like:Format.formatter ->
  Lwt_io.output_channel -> (Format.formatter -> reporter) -> reporter
val direct_reporter :
  ?like:Format.formatter ->
  output_channel -> (Format.formatter -> reporter) -> reporter

This has both kdone and I can change the reporter by using lwt_reporter or direct_reporter as long as I have a Format.formatter -> reporter to start with.

The lwt_reporter I had in mind:

let lwt_reporter ?like dst fmt_reporter =
  let buf = Buffer.create 512 in
  let ppf = Fmt.with_buffer ?like buf in
  let next = fmt_reporter ppf in
  {
    report = fun src level k kdone msgf ->
      Lwt.finalize (fun () ->
        next.report src level nop nop msgf;
        Lwt_io.write_line dst (Buffer.contents buf))
        (fun () -> kdone (); Lwt.return_unit) |> Lwt.ignore_result;
      Buffer.reset buf;
      k ()
  }
dbuenzli commented 8 years ago

In the end I didn't include a lwt reporter because Lwt_io depends on unix which is annoying for mirage and I was too lazy to add yet another library and ocamlfind package.

Thanks for the reporter blueprint, I made it type (you cannot use nop for the continuation as it constraints msgf to return a unit) and added it as an example.

edwintorok commented 8 years ago

Thanks, I like the Format.formatter parameters for Logs_fmt.reporter and Logs_lwt, I think it accomplishes exactly what I wanted. Also thanks for #10 I was actually thinking about opening a request just for that :)