# `Logger.Formatter`
[🔗](https://github.com/elixir-lang/elixir/blob/7ff272706afc522e74121493b7166719985cb099/lib/logger/lib/logger/formatter.ex#L7)

Conveniences and built-in formatter for logs.

This module 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`](`: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](https://www.erlang.org/doc/apps/kernel/logger_chapter.html#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](https://www.erlang.org/doc/apps/kernel/logger_chapter.html#formatters)
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? {: .warning}
>
> The default Logger formatter requires the user's metadata to meet
> one of the following conditions to be printed:
>
>   * Be a string (`is_binary/1`)
>   * Be a number (either `is_integer/1` or `is_float/1`)
>   * Be a PID
>   * Be an atom
>   * Be a reference
>   * Be a port
>   * Implement the `String.Chars` protocol (except for charlists)
>
> If none of the conditions above are `true`, the given metadata get
> discarded.

# `date`

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

# `date_time_ms`

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

# `new_opts`

```elixir
@type new_opts() :: [
  colors: [
    enabled: boolean(),
    debug: atom(),
    info: atom(),
    warning: atom(),
    error: atom()
  ],
  format: String.t() | {module(), atom()},
  metadata: :all | [atom()],
  truncate: pos_integer() | :infinity,
  utc_log: boolean()
]
```

# `pattern`

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

# `time_ms`

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

# `compile`

```elixir
@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`

```elixir
@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`

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

Formats date as chardata.

# `format_event`

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

Formats the message of a log event.

# `format_time`

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

Formats time as chardata.

# `new`

```elixir
@spec new(new_opts()) :: 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 `t: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`

```elixir
@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`

```elixir
@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`

```elixir
@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.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
