Packages

Is your system too quiet or too loud? Whether you want your code to speak up or shut up, control the volume of logs with LogVol, a library for increased logging resolution.

Current section

Files

Jump to
log_vol lib log_vol.ex
Raw

lib/log_vol.ex

defmodule LogVol do
@moduledoc """
Documentation for `LogVol`, a wrapper around Elixir's
native `Logger` with global volume control.
"""
@app :log_vol
@supported_volumes [
:very_verbose,
:verbose,
:normal,
:quiet,
:silent
]
@supported_levels [
:debug,
:info,
:warn,
:error
]
require Logger
@doc """
Configures the underlying Elixir `Logger`. This is a wrapper
for `Logger.configure/1` and therefore
takes the same options [found in the docs here](https://hexdocs.pm/logger/master/Logger.html#module-runtime-configuration).
"""
def configure(options) do
Logger.configure(options)
end
@doc """
Sets the logging volume for the application. There are
5 supported log volumes:
:very_verbose
:verbose
:normal
:quiet
:silent # all logs will be suppressed
Returns `:ok` if successful or returns `{:error, reason}`.
"""
def set(volume) do
unless Enum.member?(@supported_volumes, volume) do
{:error,
"Unsupported volume. Try #{Enum.join(@supported_volumes, ", ")}"}
else
Application.put_env(@app, :volume, volume)
end
end
@doc """
Same as `set/1` except raises if unsuccessful.
"""
def set!(volume) do
case set(volume) do
:ok -> :ok
{:error, reason} -> raise reason
end
end
@doc """
Sets the logging level for the application.
Attempting to log any message with severity less than the given
level will cause the message to be ignored. This is a
convenience for `LogVol.configure(level: some_level)`.
## Usage
Whereas `configure/1` supports all the options of
[`Logger.configure/1`](https://hexdocs.pm/logger/master/Logger.html#configure/1), this function only accepts LogVol's
supported levels along with:
:all - all messages will be logged, conceptually identical to :debug
:none - no messages will be logged at all
See `configure/1` for more details on runtime configuration.
Returns `:ok` if successful or `{:error, reason}` if unsuccessful.
"""
def set_level(level) do
valid_levels = @supported_levels ++ [:all, :none]
unless Enum.member?(valid_levels, level) do
{:error, "Unsupported level. Try #{Enum.join(valid_levels, ", ")}"}
else
Logger.configure(level: level)
end
end
@doc """
Same as `set_level/1` except raises if unsuccessful.
"""
def set_level!(level) do
case set_level(level) do
:ok -> :ok
{:error, reason} -> raise reason
end
end
@doc """
Returns the currently set logging volume for the application.
## Examples
iex> LogVol.volume
:normal
"""
def volume do
Application.fetch_env!(@app, :volume)
end
@doc """
Logs the debug message at the currently set volume.
If a message is not specified at a volume, nothing
will be displayed if `debug` is called at that volume.
## Usage
For convenience, `debug/1` can be given a string to log at
`:normal` volume or a keyword list of strings to log at
any volume. `debug/2` takes a string to log at `:normal` volume
and a keyword list of strings to log at other volumes.
## Examples
iex> LogVol.volume
:normal
iex> LogVol.debug("normal msg")
timestamp [debug] normal msg
:ok
iex> LogVol.set :verbose
:ok
iex> LogVol.debug("normal msg", verbose: "verbose msg")
timestamp [debug] verbose msg
:ok
iex> LogVol.debug(verbose: "verbose msg")
timestamp [debug] verbose msg
:ok
iex> LogVol.debug(very_verbose: "very verbose msg")
:noop
iex> LogVol.debug("normal msg")
:noop
"""
def debug(string_or_keyword)
def debug(string) when is_binary(string) do
string |> debug([])
end
def debug(messages) when is_list(messages) do
Keyword.get(messages, :normal) |> debug(messages)
end
@doc """
See docs for `debug/1.`
"""
def debug(string, messages) do
handle_log(:debug, string, messages)
end
@doc """
Logs the info message at the currently set volume.
If a message is not specified at a volume, nothing
will be displayed if `info` is called at that volume.
## Usage
For convenience, `info/1` can be given a string to log at
`:normal` volume or a keyword list of strings to log at
any volume. `info/2` takes a string to log at `:normal` volume
and a keyword list of strings to log at other volumes.
## Examples
iex> LogVol.volume
:normal
iex> LogVol.info("normal msg")
timestamp [info] normal msg
:ok
iex> LogVol.set :verbose
:ok
iex> LogVol.info("normal msg", verbose: "verbose msg")
timestamp [info] verbose msg
:ok
iex> LogVol.info(verbose: "verbose msg")
timestamp [info] verbose msg
:ok
iex> LogVol.info(quiet: "quiet msg")
:noop
iex> LogVol.info("normal msg")
:noop
"""
def info(string_or_keyword)
def info(string) when is_binary(string) do
string |> info([])
end
def info(messages) when is_list(messages) do
Keyword.get(messages, :normal) |> info(messages)
end
@doc """
See docs for `info/1.`
"""
def info(string, messages) do
handle_log(:info, string, messages)
end
@doc """
Logs the warn message at the currently set volume.
If a message is not specified at a volume, nothing
will be displayed if `warn` is called at that volume.
## Usage
For convenience, `warn/1` can be given a string to log at
`:normal` volume or a keyword list of strings to log at
any volume. `warn/2` takes a string to log at `:normal` volume
and a keyword list of strings to log at other volumes.
## Examples
iex> LogVol.volume
:normal
iex> LogVol.warn("normal msg")
timestamp [warn] normal msg
:ok
iex> LogVol.set :verbose
:ok
iex> LogVol.warn("normal msg", verbose: "verbose msg")
timestamp [warn] verbose msg
:ok
iex> LogVol.warn(verbose: "verbose msg")
timestamp [warn] verbose msg
:ok
iex> LogVol.warn(very_verbose: "very verbose msg")
:noop
iex> LogVol.warn("normal msg")
:noop
"""
def warn(string_or_keyword)
def warn(string) when is_binary(string) do
string |> warn([])
end
def warn(messages) when is_list(messages) do
Keyword.get(messages, :normal) |> warn(messages)
end
@doc """
See docs for `warn/1.`
"""
def warn(string, messages) do
handle_log(:warn, string, messages)
end
@doc """
Logs the error message at the currently set volume.
If a message is not specified at a volume, nothing
will be displayed if `error` is called at that volume.
## Usage
For convenience, `error/1` can be given a string to log at
`:normal` volume or a keyword list of strings to log at
any volume. `error/2` takes a string to log at `:normal` volume
and a keyword list of strings to log at other volumes.
## Examples
iex> LogVol.volume
:normal
iex> LogVol.error("normal msg")
timestamp [error] normal msg
:ok
iex> LogVol.set :verbose
:ok
iex> LogVol.error("normal msg", verbose: "verbose msg")
timestamp [error] verbose msg
:ok
iex> LogVol.error(verbose: "verbose msg")
timestamp [error] verbose msg
:ok
iex> LogVol.error(very_verbose: "very verbose msg")
:noop
iex> LogVol.error("normal msg")
:noop
"""
def error(string_or_keyword)
def error(string) when is_binary(string) do
string |> error([])
end
def error(messages) when is_list(messages) do
Keyword.get(messages, :normal) |> error(messages)
end
@doc """
See docs for `error/1.`
"""
def error(string, messages) do
handle_log(:error, string, messages)
end
@doc """
Logs the given messages at the given level, where level is
an atom from the following list of supported log levels:
#{Enum.join(@supported_levels, "\n")}
## Examples
iex> LogVol.volume
:normal
iex> LogVol.log(:debug, normal: "normal msg") # same as LogVol.debug("normal msg")
timestamp [debug] normal msg
:ok
iex> LogVol.log(:error, quiet: "quiet msg", verbose: "verbose msg")
:noop
"""
def log(level, messages) when is_list(messages) do
handle_log(level, Keyword.get(messages, :normal) , messages)
end
defp log_or_ignore(nil, _level) do
:noop
end
defp log_or_ignore(string, level) do
case level do
:debug -> Logger.debug(string)
:info -> Logger.info(string)
:warn -> Logger.warn(string)
:error -> Logger.error(string)
_ -> raise "Log level #{level} isn't supported"
end
end
defp handle_log(level, string, messages) do
case Application.fetch_env!(@app, :volume) do
:very_verbose ->
Keyword.get(messages, :very_verbose) |> log_or_ignore(level)
:verbose ->
Keyword.get(messages, :verbose) |> log_or_ignore(level)
:normal -> string |> log_or_ignore(level)
:quiet ->
Keyword.get(messages, :quiet) |> log_or_ignore(level)
_ -> :noop
end
end
end