summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorƁukasz Jan Niemier <lukasz@niemier.pl>2020-02-09 09:40:56 +0100
committerGitHub <noreply@github.com>2020-02-09 09:40:56 +0100
commit1fa3c45d1b778a24c814b97a49581af977fd61c8 (patch)
treeb90cd614836e6df74e57c949479a1704499450df
parent63118320795ee7478bf8e6751a0e09b8db9ece28 (diff)
downloadelixir-1fa3c45d1b778a24c814b97a49581af977fd61c8.tar.gz
Expose all logger levels (#9791)
-rw-r--r--lib/logger/lib/logger.ex139
-rw-r--r--lib/logger/lib/logger/handler.ex22
-rw-r--r--lib/logger/test/logger_test.exs103
3 files changed, 183 insertions, 81 deletions
diff --git a/lib/logger/lib/logger.ex b/lib/logger/lib/logger.ex
index 54990c3e3..b3ce0c447 100644
--- a/lib/logger/lib/logger.ex
+++ b/lib/logger/lib/logger.ex
@@ -30,8 +30,8 @@ defmodule Logger do
The `Logger.info/2` macro emits the provided message at the `:info`
level. Note the arguments given to `info/2` will only be evaluated
if a message is logged. For instance, if the Logger level is
- set to `:warn`, `:info` messages are never logged and therefore the
- arguments given above won't even be executed.
+ set to `:warning`, `:info` messages are never logged and therefore
+ the arguments given above won't even be executed.
There are additional macros for other levels.
@@ -44,17 +44,22 @@ defmodule Logger do
## Levels
- The supported levels, ordered by precedence, are:
+ The supported levels, ordered by importance, are:
- * `:debug` - for debug-related messages
- * `:info` - for information of any kind
- * `:warn` - for warnings
+ * `:emergency` - when system is unusable, panics
+ * `:alert` - for alerts, actions that must be taken immediately,
+ ex. corrupted database
+ * `:critical` - for critical conditions
* `:error` - for errors
+ * `:warning` - for warnings
+ * `:notice` - for normal, but signifant, messages
+ * `:info` - for information of any kind
+ * `:debug` - for debug-related messages
For example, `:info` takes precedence over `:debug`. If your log
- level is set to `:info`, `:info`, `:warn`, and `:error` will be
- printed to the console. If your log level is set to `:warn`, only
- `:warn` and `:error` will be printed.
+ level is set to `:info`, `:info`, `:warning`, and all above it will
+ be passed to backends. If your log level is set to `:alert`, only
+ `:alert` and `:emergency` will be printed.
## Metadata
@@ -188,7 +193,12 @@ defmodule Logger do
* `:level` - the logging level. Attempting to log any message
with severity less than the configured level will simply
cause the message to be ignored. Keep in mind that each backend
- may have its specific level, too.
+ may have its specific level, too. In addition to levels mentioned
+ above it also support 2 "meta-levels":
+
+ - `:all` - all messages will be logged, conceptualy identical to
+ `:debug`
+ - `:none` - no messages will be logged at all
* `:utc_log` - when `true`, uses UTC in logs. By default it uses
local time (i.e., it defaults to `false`).
@@ -214,9 +224,9 @@ defmodule Logger do
Defaults to 500 messages.
* `:discard_threshold_periodic_check` - a periodic check that
- checks and reports if logger is discarding messages. It logs a warn
+ checks and reports if logger is discarding messages. It logs a warning
message whenever the system is (or continues) in discard mode and
- it logs a warn message whenever if the system was discarding messages
+ it logs a warning message whenever if the system was discarding messages
but stopped doing so after the previous check. By default it runs
every `30_000` milliseconds.
@@ -229,7 +239,7 @@ defmodule Logger do
`config/config.exs` file:
config :logger,
- level: :warn,
+ level: :warning,
truncate: 4096
### Erlang/OTP integration
@@ -341,11 +351,11 @@ defmodule Logger do
* `:debug` - color for debug messages. Defaults to: `:cyan`
- * `:info` - color for info messages. Defaults to: `:normal`
+ * `:info` - color for info and notice messages. Defaults to: `:normal`
- * `:warn` - color for warn messages. Defaults to: `:yellow`
+ * `:warn` - color for warning messages. Defaults to: `:yellow`
- * `:error` - color for error messages. Defaults to: `:red`
+ * `:error` - color for error and higher messages. Defaults to: `:red`
See the `IO.ANSI` module for a list of colors and attributes.
@@ -403,7 +413,7 @@ defmodule Logger do
You can read more about formatting in `Logger.Formatter`, especially
if you want to support custom formatting in a custom backend.
- ### Custom backends
+ ### Elixir custom backends
Any developer can create their own `Logger` backend. Since `Logger`
is an event manager powered by `:gen_event`, writing a new backend
@@ -428,7 +438,9 @@ defmodule Logger do
* `{level, group_leader, {Logger, message, timestamp, metadata}}` where:
* `level` is one of `:debug`, `:info`, `:warn`, or `:error`, as previously
- described
+ described (for compatibility with pre 1.10 backends the `:notice` will
+ be translated to `:info` and all messages above `:error` will be translated
+ to `:error`)
* `group_leader` is the group leader of the process which logged the message
* `{Logger, message, timestamp, metadata}` is a tuple containing information
about the logged message:
@@ -508,8 +520,9 @@ defmodule Logger do
Erlang/OTP handlers must be listed under your own application:
- config :my_app, :logger,
- [:handler, :name_of_the_handler, ACustomHandler, configuration = %{}]
+ config :my_app, :logger, [
+ {:handler, :name_of_the_handler, ACustomHandler, configuration = %{}}
+ ]
And then explicitly attached in your `c:Application.start/2` callback:
@@ -525,11 +538,12 @@ defmodule Logger do
been started, which means the configuration above would have no effect.
"""
- @type level :: :error | :warn | :info | :debug
+ @type level ::
+ :emergency | :alert | :critical | :error | :warning | :warn | :notice | :info | :debug
@type backend :: :gen_event.handler()
@type message :: IO.chardata() | String.Chars.t()
@type metadata :: keyword()
- @levels [:error, :warn, :info, :debug]
+ @levels [:emergency, :alert, :critical, :error, :warning, :notice, :info, :debug]
@metadata :logger_enabled
@compile {:inline, enabled?: 1}
@@ -622,7 +636,8 @@ defmodule Logger do
@spec level() :: level()
def level() do
%{level: level} = :logger.get_primary_config()
- Logger.Handler.erlang_level_to_elixir_level(level)
+
+ level
end
@doc """
@@ -828,7 +843,7 @@ defmodule Logger do
:logger.macro_log(%{}, level, chardata, add_elixir_domain(metadata))
end
- # # TODO: Remove that in Elixir 2.0
+ # TODO: Remove that in Elixir 2.0
def __do_log__(level, other, metadata) do
IO.warn("passing #{inspect(other)} to Logger is deprecated, expected a binary or an iolist")
:logger.macro_log(%{}, level, to_string(other), add_elixir_domain(metadata))
@@ -840,61 +855,56 @@ defmodule Logger do
defp add_elixir_domain(metadata), do: Map.put(metadata, :domain, [:elixir])
- @doc """
- Logs a warning message.
-
- Returns `:ok`.
-
- ## Examples
-
- Logger.warn("knob turned too far to the right")
-
- """
- # TODO: Deprecate it in favour of `warning/1-2` macro
- defmacro warn(chardata_or_fun, metadata \\ []) do
- maybe_log(:warn, chardata_or_fun, metadata, __CALLER__)
- end
+ messages = [
+ # Airplane 2
+ "We are also out of coffee",
+ # Red Alert 2
+ "Kirov reporting",
+ # Spies like us
+ "Doctor? Doctor",
+ # 2001: Space Odyssey
+ "I'm sory Dave",
+ # Lost in Space
+ "Danger, Will Robinson",
+ # The Graduate
+ "Mrs. Robinson, you are trying to seduce me",
+ # Dr. No
+ "Bond. James Bond.",
+ # A Bug's Life
+ "I'm the only stick with eyeballs"
+ ]
- @doc """
- Logs an info message.
+ for {level, message} <- Enum.zip(@levels, messages) do
+ @doc """
+ Logs a #{level} message.
- Returns `:ok`.
+ Returns `:ok`.
- ## Examples
+ ## Examples
- Logger.info("mission accomplished")
+ Logger.#{level}("#{message}")
- """
- defmacro info(chardata_or_fun, metadata \\ []) do
- maybe_log(:info, chardata_or_fun, metadata, __CALLER__)
+ """
+ defmacro unquote(level)(chardata_or_fun, metadata \\ []) do
+ maybe_log(unquote(level), chardata_or_fun, metadata, __CALLER__)
+ end
end
@doc """
- Logs an error message.
+ Logs a warning message.
Returns `:ok`.
- ## Examples
-
- Logger.error("oops")
-
- """
- defmacro error(chardata_or_fun, metadata \\ []) do
- maybe_log(:error, chardata_or_fun, metadata, __CALLER__)
- end
-
- @doc """
- Logs a debug message.
-
- Returns `:ok`.
+ This macro is deprecated in favour of `warning/2`.
## Examples
- Logger.debug("hello?")
+ Logger.warn("knob turned too far to the right")
"""
- defmacro debug(chardata_or_fun, metadata \\ []) do
- maybe_log(:debug, chardata_or_fun, metadata, __CALLER__)
+ # TODO: Hard deprecate it in favour of `warning/1-2` macro
+ defmacro warn(chardata_or_fun, metadata \\ []) do
+ maybe_log(:warning, chardata_or_fun, metadata, __CALLER__)
end
@doc """
@@ -902,7 +912,8 @@ defmodule Logger do
Returns `:ok`.
- The macros `debug/2`, `warn/2`, `info/2`, and `error/2` are
+ The macros `debug/2`, `info/2`, `notice/2`, `warning/2`,
+ `error/2`, `critical/2`, `alert/2`, and `emergency/2` are
preferred over this macro as they can automatically eliminate
the call to `Logger` altogether at compile time if desired
(see the documentation for the `Logger` module).
diff --git a/lib/logger/lib/logger/handler.ex b/lib/logger/lib/logger/handler.ex
index 50fd240af..f522021fc 100644
--- a/lib/logger/lib/logger/handler.ex
+++ b/lib/logger/lib/logger/handler.ex
@@ -6,17 +6,17 @@ defmodule Logger.Handler do
## Conversions
- # TODO: Remove this mapping once we support all of Erlang types
- def erlang_level_to_elixir_level(:none), do: :error
- def erlang_level_to_elixir_level(:emergency), do: :error
- def erlang_level_to_elixir_level(:alert), do: :error
- def erlang_level_to_elixir_level(:critical), do: :error
- def erlang_level_to_elixir_level(:error), do: :error
- def erlang_level_to_elixir_level(:warning), do: :warn
- def erlang_level_to_elixir_level(:notice), do: :info
- def erlang_level_to_elixir_level(:info), do: :info
- def erlang_level_to_elixir_level(:debug), do: :debug
- def erlang_level_to_elixir_level(:all), do: :debug
+ # TODO: Remove this mapping once we support all of Erlang types (2.0)
+ defp erlang_level_to_elixir_level(:none), do: :error
+ defp erlang_level_to_elixir_level(:emergency), do: :error
+ defp erlang_level_to_elixir_level(:alert), do: :error
+ defp erlang_level_to_elixir_level(:critical), do: :error
+ defp erlang_level_to_elixir_level(:error), do: :error
+ defp erlang_level_to_elixir_level(:warning), do: :warn
+ defp erlang_level_to_elixir_level(:notice), do: :info
+ defp erlang_level_to_elixir_level(:info), do: :info
+ defp erlang_level_to_elixir_level(:debug), do: :debug
+ defp erlang_level_to_elixir_level(:all), do: :debug
# TODO: Warn on deprecated level
def elixir_level_to_erlang_level(:warn), do: :warning
diff --git a/lib/logger/test/logger_test.exs b/lib/logger/test/logger_test.exs
index 20722402d..e9c0b397c 100644
--- a/lib/logger/test/logger_test.exs
+++ b/lib/logger/test/logger_test.exs
@@ -89,14 +89,35 @@ defmodule LoggerTest do
test "level/0" do
assert Logger.level() == :debug
+ Logger.configure(level: :all)
+ assert Logger.level() == :all
+
Logger.configure(level: :info)
assert Logger.level() == :info
+ Logger.configure(level: :notice)
+ assert Logger.level() == :notice
+
Logger.configure(level: :warn)
- assert Logger.level() == :warn
+ assert Logger.level() == :warning
+
+ Logger.configure(level: :warning)
+ assert Logger.level() == :warning
Logger.configure(level: :error)
assert Logger.level() == :error
+
+ Logger.configure(level: :critical)
+ assert Logger.level() == :critical
+
+ Logger.configure(level: :alert)
+ assert Logger.level() == :alert
+
+ Logger.configure(level: :emergency)
+ assert Logger.level() == :emergency
+
+ Logger.configure(level: :none)
+ assert Logger.level() == :none
after
Logger.configure(level: :debug)
end
@@ -193,8 +214,13 @@ defmodule LoggerTest do
test "compare_levels/2" do
assert Logger.compare_levels(:debug, :debug) == :eq
assert Logger.compare_levels(:debug, :info) == :lt
+ assert Logger.compare_levels(:debug, :notice) == :lt
assert Logger.compare_levels(:debug, :warn) == :lt
+ assert Logger.compare_levels(:debug, :warning) == :lt
assert Logger.compare_levels(:debug, :error) == :lt
+ assert Logger.compare_levels(:debug, :critical) == :lt
+ assert Logger.compare_levels(:debug, :alert) == :lt
+ assert Logger.compare_levels(:debug, :emergency) == :lt
assert Logger.compare_levels(:info, :debug) == :gt
assert Logger.compare_levels(:info, :info) == :eq
@@ -232,15 +258,29 @@ defmodule LoggerTest do
assert Logger.info("hello", []) == :ok
end) =~ msg_with_meta("[info] hello")
- assert capture_log(:warn, fn ->
+ assert capture_log(:notice, fn ->
assert Logger.info("hello", []) == :ok
end) == ""
- assert capture_log(:warn, fn ->
+ assert capture_log(:notice, fn ->
assert Logger.info(raise("not invoked"), []) == :ok
end) == ""
end
+ test "warning/2" do
+ assert capture_log(fn ->
+ assert Logger.warning("hello", []) == :ok
+ end) =~ msg_with_meta("[warn] hello")
+
+ assert capture_log(:error, fn ->
+ assert Logger.warning("hello", []) == :ok
+ end) == ""
+
+ assert capture_log(:error, fn ->
+ assert Logger.warning(raise("not invoked"), []) == :ok
+ end) == ""
+ end
+
test "warn/2" do
assert capture_log(fn ->
assert Logger.warn("hello", []) == :ok
@@ -259,6 +299,56 @@ defmodule LoggerTest do
assert capture_log(fn ->
assert Logger.error("hello", []) == :ok
end) =~ msg_with_meta("[error] hello")
+
+ assert capture_log(:critical, fn ->
+ assert Logger.error("hello", []) == :ok
+ end) == ""
+
+ assert capture_log(:critical, fn ->
+ assert Logger.error(raise("not invoked"), []) == :ok
+ end) == ""
+ end
+
+ test "critical/2" do
+ assert capture_log(fn ->
+ assert Logger.critical("hello", []) == :ok
+ end) =~ msg_with_meta("[error] hello")
+
+ assert capture_log(:alert, fn ->
+ assert Logger.critical("hello", []) == :ok
+ end) == ""
+
+ assert capture_log(:alert, fn ->
+ assert Logger.critical(raise("not invoked"), []) == :ok
+ end) == ""
+ end
+
+ test "alert/2" do
+ assert capture_log(fn ->
+ assert Logger.alert("hello", []) == :ok
+ end) =~ msg_with_meta("[error] hello")
+
+ assert capture_log(:emergency, fn ->
+ assert Logger.alert("hello", []) == :ok
+ end) == ""
+
+ assert capture_log(:emergency, fn ->
+ assert Logger.alert(raise("not invoked"), []) == :ok
+ end) == ""
+ end
+
+ test "emergency/2" do
+ assert capture_log(fn ->
+ assert Logger.emergency("hello", []) == :ok
+ end) =~ msg_with_meta("[error] hello")
+
+ assert capture_log(:none, fn ->
+ assert Logger.emergency("hello", []) == :ok
+ end) == ""
+
+ assert capture_log(:none, fn ->
+ assert Logger.emergency(raise("not invoked"), []) == :ok
+ end) == ""
end
end
@@ -290,6 +380,7 @@ defmodule LoggerTest do
def level_filter do
Logger.info("info_filter")
Logger.warn("warn_filter")
+ Logger.warning("warning_filter")
end
def works do
@@ -437,7 +528,7 @@ defmodule LoggerTest do
log =
capture_log(fn ->
:sys.suspend(Logger)
- for _ <- 1..10, do: Logger.warn("warning!")
+ for _ <- 1..10, do: Logger.warning("warning!")
:sys.resume(Logger)
Logger.flush()
@@ -496,10 +587,10 @@ defmodule LoggerTest do
assert capture_log(fn -> Logger.info("hello") end) =~ "hello"
:logger.set_primary_config(:level, :notice)
- assert Logger.level() == :info
+ assert Logger.level() == :notice
:logger.set_primary_config(:level, :emergency)
- assert Logger.level() == :error
+ assert Logger.level() == :emergency
after
Logger.configure(level: :debug)
end