View Source Logger.Formatter (Logger v1.14.5)
Conveniences for formatting data for logs.
This module allows developers to specify a {module, function}
or a string that serves as template for log messages.
Formatting string
The log messages can be controlled by a formatting string.
Here is an example of how to configure the :console
backend
in a config/config.exs
file:
For example:
config :logger, :console,
format: "$time $metadata[$level] $message\n"
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
Backends typically allow developers to supply such control
strings via configuration files. This module provides compile/1
,
which compiles the string into a format for fast operations at
runtime and format/5
to format the compiled pattern into an
actual IO data.
Formatting function
You can also customize the format of your log messages to a
{module, function}
tuple if you wish to provide your own
format function. Here is an example of how to configure the
:console
backend in a config/config.exs
file:
config :logger, :console,
format: {MyConsoleLogger, :format}
And here is an example of how you can define MyConsoleLogger.format/4
from the above configuration:
defmodule MyConsoleLogger do
@spec format(atom, term, Logger.Formatter.time(), keyword()) :: IO.chardata()
def format(level, message, timestamp, metadata) do
# Custom formatting logic that must return chardata.
# ...
end
end
The format/4
function must not fail. If it does, it will bring
that particular logger instance down, causing your system to temporarily
lose log messages. If necessary, wrap the function in a rescue
and
log a default message instead:
defmodule MyConsoleLogger do
def format(level, message, timestamp, metadata) do
# Custom formatting logic
rescue
_ -> "could not format: #{inspect({level, message, metadata})}"
end
end
The {module, function}
will be invoked with four arguments:
- the log level: an atom (
atom/0
) - the message: this is usually
IO.chardata/0
, but in some cases it may contain invalid data. Since the formatting function must never fail, you need to prepare for the message being anything - the current timestamp: a term of type
Logger.Formatter.time/0
- the metadata: a keyword list (
keyword/0
)
The {module, function}
must return a term of type IO.chardata/0
.
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.
Link to this section Summary
Functions
Compiles a format string into a data structure that format/5
can handle.
Takes a compiled format and injects the level, timestamp, message, and metadata keyword list and returns a properly formatted string.
Formats date as chardata.
Formats time as chardata.
Prunes invalid Unicode code points from lists and invalid UTF-8 bytes.
Link to this section Types
@type pattern() :: :date | :level | :levelpad | :message | :metadata | :node | :time
@type time() :: {{1970..10000, 1..12, 1..31}, {0..23, 0..59, 0..59, 0..999}}
Link to this section Functions
@spec compile(binary() | nil) :: [pattern() | binary()]
@spec compile(pattern) :: pattern when pattern: {module(), function :: atom()}
Compiles a format string 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 through a custom formatter, you can
pass a {module, function}
tuple as the pattern
.
iex> Logger.Formatter.compile("$time $metadata [$level] $message\n")
[:time, " ", :metadata, " [", :level, "] ", :message, "\n"]
iex> Logger.Formatter.compile({MyLoggerFormatter, :format})
{MyLoggerFormatter, :format}
@spec format( mod_and_fun | [pattern() | binary()], Logger.level(), Logger.message(), time(), keyword() ) :: IO.chardata() when mod_and_fun: {atom(), atom()}
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. See Logger.Backends.Console
for more
information on this.
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"
@spec format_date({1970..10000, 1..12, 1..31}) :: IO.chardata()
Formats date as chardata.
@spec format_time({0..23, 0..59, 0..59, 0..999}) :: IO.chardata()
Formats time as chardata.
@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.