viodotcom / meta_logger

A wrapper for Elixir Logger that keeps and returns the logger metadata from the caller processes.
Apache License 2.0
20 stars 2 forks source link

Allow passing a custom slicer module in the middleware options. #22

Open Ivor opened 3 days ago

Ivor commented 3 days ago

Some scenarios might require a particular way of slicing the entries, for example, ensuring that each slice is valid UTF-8. This would be a requirement if the entries are later used as part of a JSON payload.

Currently the Tesla.Middleware includes a slicer module but this module cannot be configured by users.

The proposal is it add an option that will allow users to pass in their custom Slicer module.

Usage example:

defmodule MyClient do
  use Tesla

  plug Tesla.Middleware.MetaLogger,
    filter_body: {~r/email=.*&/, "email=[FILTERED]&"}
    filter_headers: ["authorization"],
    filter_query_params: [:api_key],
    log_level: :debug,
    log_tag: MyApp,
    max_entry_length: 22_000,
    slicer: MyCustomerSlicer
end

defmodule MyCustomSlicer do
  @impl MetaLogger.Slicer
  def slice(entry, max_entry_length) do
     String.slice(entry, 0, max_entry_length)
  end
end

Assuming a default implementation for the current slicing behaviour, adding this line to prepare_options/2 function in Tesla.Middleware.MetaLogger

|> maybe_put_default_value(:slicer, MetaLogger.Slicer.DefaultImpl)

And converting the log/3 function to this:

defp log(message, level, options) when is_binary(message) do
  max_entry_length = Keyword.get(options, :max_entry_length)
  slicer = Keyword.get(options, :slicer)

  message
  |> slicer.slice(max_entry_length)
  |> Enum.map(&prepend_tag(&1, options))
  |> Enum.each(&MetaLogger.log(level, &1))
end

will make this possible and allow for more flexible log slicing.