RingLogger (ring_logger v0.11.4)

View Source

This is an in-memory ring buffer backend for the Elixir Logger.

Install it by adding it to your config.exs:

import Config

# Add the RingLogger backend. This removes the default :console backend.
config :logger, backends: [RingLogger]

# Periodically save logs to a file, and load logs on GenServer start from this file
config :logger, RingLogger, persist_path: "./myapp.log", persist_seconds: 300

# Save messages to one circular buffer that holds 1024 entries.
config :logger, RingLogger, max_size: 1024

# Separate out `:error` and `:warning` messages to their own circular buffer.
# All other log messages are stored in the default circular buffer.
config :logger, RingLogger, buffers: %{
  errors: %{
    levels: [:error, :warning],
    max_size: 1024
  }
}

# Specify circular buffers for all log levels. The default circular buffer won't
# be used in this example configuration.
config :logger, RingLogger, buffers: %{
  low_priority: %{
    levels: [:warning, :notice, :info, :debug],
    max_size: 1024
  },
  high_priority: %{
    levels: [:emergency, :alert, :critical, :error],
    max_size: 1024
  }
}

Or add manually:

Logger.add_backend(RingLogger)
Logger.configure_backend(RingLogger, max_size: 1024)

Once added as a backend, you have two options depending on whether you're accessing the RingLogger via the IEx prompt or via code. If you're at the IEx prompt, use the helper methods in here like attach, detach, next, tail, grep, etc. They'll automate a few things behind the scenes. If you're writing a program that needs to get log messages, use get or start_link a RingLogger.Client and call its methods directly.

Summary

Types

Options to define a separate buffer based on log levels

Option values used by client-side functions like attach and tail

Option list for client-side functions

A map holding a raw, unformatted log entry

Callback function for printing/paging tail, grep, and next output

Option values used by the ring logger

Functions

Attach the current IEx session to the logger. It will start printing log messages.

Fetch the current configuration for the attached client

Update the logger configuration.

Count the next messages in the log

Detach the current IEx session from the logger

Helper method for formatting log messages per the current client's configuration.

Get n log messages starting at the specified index.

Run a regular expression on each entry in the log and print out the matchers.

Return a list of formatted log entries that match the given metadata key-value pair.

Print the next messages in the log

Reset the index into the log for next/1 to the oldest entry.

Save the contents of the log to the specified path

Print the last 10 messages

Print the last messages in the log

Print the last n messages in the log

Starts the Ring Logger Viewer TUI app on the current prompt

Types

buffer()

@type buffer() :: %{levels: [Logger.level()], max_size: pos_integer()}

Options to define a separate buffer based on log levels

client_option()

@type client_option() ::
  {:io, term()}
  | {:pager, pager_fun()}
  | {:color, term()}
  | {:metadata, Logger.metadata()}
  | {:format, String.t() | custom_formatter()}
  | {:level, Logger.level()}
  | {:module_levels, map()}
  | {:application_levels, map()}

Option values used by client-side functions like attach and tail

client_options()

@type client_options() :: [client_option()]

Option list for client-side functions

entry()

@type entry() :: %{
  level: Logger.level(),
  module: module(),
  message: Logger.message(),
  timestamp: {{1970..10000, 1..12, 1..31}, {0..23, 0..59, 0..59, 0..999}},
  metadata: Logger.metadata()
}

A map holding a raw, unformatted log entry

pager_fun()

@type pager_fun() :: (IO.device(), IO.chardata() -> :ok | {:error, term()})

Callback function for printing/paging tail, grep, and next output

server_option()

@type server_option() ::
  {:max_size, pos_integer()}
  | {:buffers, %{required(term()) => buffer()}}
  | {:persist_path, String.t()}
  | {:persist_seconds, pos_integer()}

Option values used by the ring logger

Functions

attach(opts \\ [])

@spec attach(client_options()) :: :ok | {:error, :no_client}

Attach the current IEx session to the logger. It will start printing log messages.

Options include:

  • :io - output location when printing. Defaults to :stdio
  • :colors - a keyword list of coloring options
  • :metadata - a keyword list of additional metadata
  • :format - the format message used to print logs
  • :level - the minimum log level to report by this backend. Note that the :logger application's :level setting filters log messages prior to RingLogger.
  • :module_levels - a map of log level overrides per module. For example, %{MyModule => :error, MyOtherModule => :none}
  • :application_levels - a map of log level overrides per application. For example, %{:my_app => :error, :my_other_app => :none}. Note log levels set in :module_levels will take precedence.

config()

@spec config() :: client_options() | {:error, :no_client}

Fetch the current configuration for the attached client

configure(opts)

@spec configure([server_option()]) :: :ok

Update the logger configuration.

Options include:

  • :max_size - the max number of log messages to store at a time

count_next(opts \\ [])

@spec count_next(client_options()) :: non_neg_integer()

Count the next messages in the log

NOTE: This function may change in future releases.

Options include:

  • Options from attach/1
  • :pager - a function for printing log messages to the console. Defaults to IO.binwrite/2.

detach()

@spec detach() :: :ok

Detach the current IEx session from the logger

format(message)

@spec format(entry()) :: :ok | {:error, :no_client}

Helper method for formatting log messages per the current client's configuration.

get(index \\ 0, n \\ 0)

@spec get(non_neg_integer(), non_neg_integer()) :: [entry()]

Get n log messages starting at the specified index.

Set n to 0 to get entries to the end

grep(regex_or_string, opts \\ [])

@spec grep(Regex.t() | String.t(), client_options()) :: :ok | {:error, term()}

Run a regular expression on each entry in the log and print out the matchers.

For example:

iex> RingLogger.grep(~r/something/) :ok

Options include:

  • Options from attach/1
  • :pager - a function for printing log messages to the console. Defaults to IO.binwrite/2.
  • :before - Number of lines before the match to include
  • :after - NUmber of lines after the match to include

grep_metadata(key, match_value)

@spec grep_metadata(atom(), String.t() | Regex.t()) :: :ok | {:error, term()}

Return a list of formatted log entries that match the given metadata key-value pair.

For example:

iex> RingLogger.grep_metadata(:session_id, "abc") :ok

iex> RingLogger.grep_metadata(:session_id, ~r/something/) :ok

next(opts \\ [])

@spec next(client_options()) :: :ok | {:error, term()}

Print the next messages in the log

Options include:

  • Options from attach/1
  • :pager - a function for printing log messages to the console. Defaults to IO.binwrite/2.

reset(opts \\ [])

@spec reset(client_options()) :: :ok | {:error, term()}

Reset the index into the log for next/1 to the oldest entry.

save(path)

@spec save(Path.t()) :: :ok | {:error, term()}

Save the contents of the log to the specified path

The file is overwritten if it already exists. Log message formatting is done similarly to other RingLogger calls.

tail()

@spec tail() :: :ok

Print the last 10 messages

tail(opts)

@spec tail(non_neg_integer() | client_options()) :: :ok

Print the last messages in the log

See tail/2.

tail(n, opts)

@spec tail(non_neg_integer(), client_options()) :: :ok

Print the last n messages in the log

Options include:

  • Options from attach/1
  • :pager - a function for printing log messages to the console. Defaults to IO.binwrite/2.

viewer()

@spec viewer() :: :ok

Starts the Ring Logger Viewer TUI app on the current prompt