diff options
author | Ćukasz Jan Niemier <lukasz@niemier.pl> | 2020-02-09 09:40:56 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-09 09:40:56 +0100 |
commit | 1fa3c45d1b778a24c814b97a49581af977fd61c8 (patch) | |
tree | b90cd614836e6df74e57c949479a1704499450df | |
parent | 63118320795ee7478bf8e6751a0e09b8db9ece28 (diff) | |
download | elixir-1fa3c45d1b778a24c814b97a49581af977fd61c8.tar.gz |
Expose all logger levels (#9791)
-rw-r--r-- | lib/logger/lib/logger.ex | 139 | ||||
-rw-r--r-- | lib/logger/lib/logger/handler.ex | 22 | ||||
-rw-r--r-- | lib/logger/test/logger_test.exs | 103 |
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 |