Skip to content

akasprzok/logfmt_ex

Repository files navigation

main Hex Hex Docs License Coverage Status

LogfmtEx

A log formatter for the logfmt format popularized by Heroku.

Logger.info("I am a message", user_id: 123)
level=info msg="I am a message" ts="12:38:38.055 1973-03-12" user_id=123 pid=#PID<0.223.0> file=test/logfmt_ex_test.exs

Installation

The package can be installed by adding logfmt_ex to your list of dependencies in mix.exs:

def deps do
  [
    {:logfmt_ex, "~> 0.4"}
  ]
end

In your app's logger configuration, specify the LogfmtEx module and its format function to be used to format your logs:

config :logger, :console,
  format: {LogfmtEx, :format}

You can customize the formatting in your config:

config :logfmt_ex, :opts,
  message_key: "msg",
  timestamp_key: "ts",
  timestamp_format: :iso8601

Configuration

  • :delimiter - defaults to =.
  • :format - A list of atoms that defines the order in which key/value pairs will written to the log line. Defaults to [:timestamp, :level, :message, :metadata]. Valid parameters are
    • :timestamp - the timestamp of the log message
    • :level - the log level
    • :message - the log message itself
    • :metadata - metadata as key=value paris
    • :node - the node name
  • timestamp_key - changes the key used for the timestamp field. Defaults to timestamp.
  • timestamp_format - How the timestamp is formatted. Defaults to :elixir. The options are
    • :elixir - Uses the same formatting functions found in the standard elixir log formatter. Example: "12:38:38.055 1973-03-12"
    • :epoch_seconds - outputs an integer representing the number of seconds elapsed since January 1, 1970. Only useful for applications that emit logs sporadically.
    • :iso8601 - Formats the timestamp according to ISO8601-2019. Example: 2000-02-29T23:00:07
  • level_key - the key used for the log level. Defaults to level.
  • message_key - the key used for the message field. Defaults to message, but msg is a popular alternative.

Encoding

Structs can be encoded via the ValueEncoder protocol.

defmodule User do
  defstruct [:email, :name, :id]

  defimpl LogfmtEx.ValueEncoder do
    @doc """
    As we don't want to leak PII into our logs, we encode the struct to just the user's ID.
    """
    def encode(user), do: to_string(user.id)
  end

Types for which the protocol is not implemented will fall back to the to_string/1 function in the String.Chars protocol. If the term being encoded does not implement that protocol, the formatter will fall back to the Inspect protocol.

Note that the algebra documents produced by Kernel.inspect/1 don't lend themselves to logfmt - this fallback is provided to minimize the chance that the formatter fails, instead making a "best effort" at producing usable output. It is recommended to implement either the LogfmtEx.ValueEncoder or String.Chars protocol for any data structures that might find their way into your logs.

Testing and Development

This library uses asdf to manage runtime versions of Elixir and Erlang. Contributions, issues, and all other feedback is more than welcome!

Benchmarks

the /benchmarks folder includes benchmarks comparing LogfmtEx to Logger.Formatter.

You can run them with mix run benchmarks/throughput.exs.

Alternatives

LogfmtEx is a simple logfmt formatter specifically for the Elixir console backend. If you're looking for a library to encode and decode logfmt, take a look at logfmt-elixir instead.