View Source Logger.Formatter (Logger v1.19.0-dev)

Conveniences and built-in formatter for logs.

This modules defines a suitable :logger formatter which formats messages and reports as Elixir terms and also provides additional functionality, such as timezone conversion, truncation, and coloring. This formatter is used by default by Logger and you can configure it using:

config :logger, :default_formatter,
  format: "\n$time $metadata[$level] $message\n",
  metadata: [:user_id]

You can also use Logger.Formatter.new/1 to create your own formatter, which can then be passed as a formatter to any :logger_handler. See Logger.Formatter.new/1 for all configuration options.

This module also provides several conveniences for those who wish to write their custom logger formatters.

Formatting

The log messages can be controlled by a formatting string. Here is an example:

config :logger, :default_formatter,
  format: "\n$time $metadata[$level] $message\n",
  metadata: [:user_id]

The above will print error messages as:

18:43:12.439 user_id=13 [error] Hello\n

The valid parameters you can use are:

  • $time - the time the log message was sent
  • $date - the date the log message was sent
  • $message - the log message
  • $level - the log level
  • $node - the node that prints the message
  • $metadata - user controlled data presented in "key=val key2=val2 " format

Formatting function

You can also customize the format of your log messages with a {module, function_name} tuple if you wish to change how messages are formatted but keep all other features provided by Logger.Formatter such as truncation and coloring. However, if you want to get full control of formatting, consider writing a custom :logger formatter instead, which has complete access to all events and metadata.

When using a {module, function_name}, the function will be invoked with the level, the message, the timestamp, and metadata, like this:

defmodule MyConsoleLogger do
  @spec format(atom, chardata, Logger.Formatter.date_time_ms(), keyword()) :: IO.chardata()
  def format(level, message, timestamp, metadata) do
    # Custom formatting logic that must return chardata.
    # ...
  end
end

Metadata

Metadata to be sent to the logger can be read and written with the Logger.metadata/0 and Logger.metadata/1 functions. For example, you can set Logger.metadata([user_id: 13]) to add user_id metadata to the current process. The user can configure the backend to choose which metadata it wants to print and it will replace the $metadata value.

When is user metadata printed?

The default Logger formatter requires the user's metadata to meet one of the following conditions to be printed:

If none of the conditions above are true, the given metadata get discarded.

Summary

Functions

Compiles a pattern or function into a data structure that format/5 can handle.

Formats date as chardata.

Formats the message of a log event.

Formats time as chardata.

Initializes a formatter for :logger handlers.

Prunes invalid Unicode code points from lists and invalid UTF-8 bytes.

Converts the system time (in microseconds) from metadata into a date_time_ms tuple.

Truncates a chardata into n bytes.

Types

date()

@type date() :: {1970..10000, 1..12, 1..31}

date_time_ms()

@type date_time_ms() :: {date(), time_ms()}

pattern()

@type pattern() :: :date | :level | :levelpad | :message | :metadata | :node | :time

time_ms()

@type time_ms() :: {0..23, 0..59, 0..59, 0..999}

Functions

compile(pattern_or_function)

@spec compile(binary() | nil) :: [pattern() | binary()]
@spec compile(pattern) :: pattern when pattern: {module(), function :: atom()}

Compiles a pattern or function into a data structure that format/5 can handle.

Check the module doc for documentation on the valid parameters that will be interpolated in the pattern. If you pass nil as the pattern, the pattern defaults to:

"\n$time $metadata[$level] $message\n"

If you want to customize formatting with a custom function, you can pass a {module, function_name} tuple.

This function, alongside format/5, is the main building block used by Logger.Formatter.new/1 for formatting messages. It can also be used by those interested in building custom formatters.

Examples

iex> Logger.Formatter.compile("$time $metadata [$level] $message\n")
[:time, " ", :metadata, " [", :level, "] ", :message, "\n"]

iex> Logger.Formatter.compile({MyLoggerFormatter, :format})
{MyLoggerFormatter, :format}

format(pattern_or_function, level, message, timestamp, metadata)

@spec format(
  mod_and_fun | [pattern() | binary()],
  Logger.level(),
  Logger.message(),
  date_time_ms(),
  keyword()
) :: IO.chardata()
when mod_and_fun: {atom(), atom()}

Formats a pattern_or_function returned by compile/1.

It takes a compiled format and injects the level, timestamp, message, and metadata keyword list and returns a properly formatted string.

If pattern_or_function is a {module, function_name} tuple, then module.function_name(level, message, timestamp, metadata) is invoked to get the message.

This function, alongside compile/1, is the main building block used by Logger.Formatter.new/1 for formatting messages. It can also be used by those interested in building custom formatters.

Examples

iex> pattern = Logger.Formatter.compile("[$level] $message")
iex> timestamp = {{1977, 01, 28}, {13, 29, 00, 000}}
iex> formatted = Logger.Formatter.format(pattern, :info, "hello", timestamp, [])
iex> IO.chardata_to_string(formatted)
"[info] hello"

format_date(date_tuple)

@spec format_date(date()) :: IO.chardata()

Formats date as chardata.

format_event(log_event, truncate)

@spec format_event(:logger.log_event(), pos_integer() | :infinity) :: IO.chardata()

Formats the message of a log event.

format_time(time_ms_tuple)

@spec format_time(time_ms()) :: IO.chardata()

Formats time as chardata.

new(options \\ [])

@spec new(keyword()) :: formatter when formatter: term()

Initializes a formatter for :logger handlers.

The supported options are:

  • :colors - a keyword list of coloring options.

  • :format - the format message used to print logs. Defaults to: "\n$time $metadata[$level] $message\n". It may also be a {module, function_name} tuple that is invoked with the log level, the message, the current timestamp and the metadata and must return IO.chardata/0. See the module docs for more information on :format.

  • :metadata - a list of metadata keys to be printed by $metadata. Defaults to an empty list (no metadata). Setting :metadata to :all prints all metadata. See the "Metadata" section in the Logger documentation for more information.

  • :truncate - the maximum message size to be logged (in bytes). Defaults to 8192 bytes. Note this configuration is approximate. Truncated messages will have " (truncated)" at the end. The atom :infinity can be passed to disable this behavior.

  • :utc_log - when true, uses UTC in logs. By default it uses local time (as it defaults to false).

The supported keys in the :colors keyword list are:

  • :enabled - boolean value that allows for switching the coloring on and off. Defaults to: IO.ANSI.enabled?/0

  • :debug - color for debug messages. Defaults to: :cyan

  • :info - color for info and notice messages. Defaults to: :normal

  • :warning - color for warning messages. Defaults to: :yellow

  • :error - color for error and higher messages. Defaults to: :red

See the IO.ANSI module for a list of colors and attributes. The color of the message can also be configured per message via the :ansi_color metadata.

prune(binary)

@spec prune(IO.chardata()) :: IO.chardata()

Prunes invalid Unicode code points from lists and invalid UTF-8 bytes.

Typically called after formatting when the data cannot be printed.

system_time_to_date_time_ms(system_time, utc_log? \\ false)

@spec system_time_to_date_time_ms(integer(), boolean()) :: date_time_ms()

Converts the system time (in microseconds) from metadata into a date_time_ms tuple.

truncate(chardata, n)

@spec truncate(IO.chardata(), non_neg_integer() | :infinity) :: IO.chardata()

Truncates a chardata into n bytes.

There is a chance we truncate in the middle of a grapheme cluster but we never truncate in the middle of a binary code point. For this reason, truncation is not exact.