Call for testers: new Elixir Logger backend

Very excited about this. Thanks for all your work!

I’m curious what approach you have in mind for structured logging. So far I’ve been doing it this way:

  • At the call site, pass structured data via metadata:
      Logger.log(level, "Processing request",
        method: conn.method,
        path: conn.request_path,
        ...
      )
    
  • Define a custom formatter which takes all metadata:
    config :logger, :file_log,
      path: "app.log",
      level: :info,
      format: {MyApp.Logger, :format},
      metadata: :all
    
  • In the formatter, generate JSON, roughly like:
    def format(level, message, timestamp, metadata) do
     %{
        "timestamp" => format_timestamp(timestamp),
        "level" => level,
        "message" => IO.iodata_to_binary(message)
      }
      |> add_metadata(metadata)
      |> Jason.encode!()
    end
    
    where add_metadata reads each key/value pair from metadata, converts the value to a printable representation, and adds it to the event map, similar to Honeybadger.JSON.

It works, but it’s not ideal - we had to reimplement functionality from the default formatter, for instance formatting time or converting PIDs to strings. OTP reports also can’t be structured, because they’re a string blob by the time they reach the formatter (not a huge deal though).

Could we achieve JSON logging more easily with the new backend, or with future development?

3 Likes