1defmodule Logger.App do 2 @moduledoc false 3 4 require Logger 5 6 use Application 7 8 @doc false 9 def start(_type, _args) do 10 start_options = Application.get_env(:logger, :start_options) 11 otp_reports? = Application.fetch_env!(:logger, :handle_otp_reports) 12 counter = :counters.new(1, [:atomics]) 13 14 children = [ 15 %{ 16 id: :gen_event, 17 start: {:gen_event, :start_link, [{:local, Logger}, start_options]}, 18 modules: :dynamic 19 }, 20 {Logger.Watcher, {Logger.Config, counter}}, 21 Logger.BackendSupervisor 22 ] 23 24 case Supervisor.start_link(children, strategy: :rest_for_one, name: Logger.Supervisor) do 25 {:ok, sup} -> 26 primary_config = add_elixir_handler(otp_reports?, counter) 27 28 default_handlers = 29 if otp_reports? do 30 delete_erlang_handler() 31 else 32 [] 33 end 34 35 handlers = [{:primary, primary_config} | default_handlers] 36 {:ok, sup, handlers} 37 38 {:error, _} = error -> 39 error 40 end 41 end 42 43 @doc false 44 def start do 45 Application.start(:logger) 46 end 47 48 @doc false 49 def stop(handlers) do 50 _ = :logger.remove_handler(Logger) 51 _ = :logger.remove_primary_filter(:process_disabled) 52 add_handlers(handlers) 53 54 :logger.add_primary_filter( 55 :silence_logger_exit, 56 {&Logger.Filter.silence_logger_exit/2, []} 57 ) 58 end 59 60 @doc false 61 def config_change(changed, _new, _removed) do 62 # All other config has already been persisted, we only need to 63 # update the level and reload the logger state. 64 Logger.configure(Keyword.take(changed, [:level])) 65 end 66 67 @doc """ 68 Stops the application without sending messages to error logger. 69 """ 70 def stop() do 71 Application.stop(:logger) 72 end 73 74 defp add_elixir_handler(otp_reports?, counter) do 75 config = %{ 76 level: :all, 77 config: %{counter: counter}, 78 filter_default: :log, 79 filters: 80 if not otp_reports? do 81 [filter_elixir_domain: {&Logger.Filter.filter_elixir_domain/2, []}] 82 else 83 [] 84 end 85 } 86 87 %{level: erl_level} = primary_config = :logger.get_primary_config() 88 89 # Elixir's logger level is no longer set by default. 90 # 91 # If it is set, it always has higher precedence, but we warn 92 # in case of mismatches. 93 # 94 # If it is not set, we revert Erlang's kernel to debug, if it 95 # has its default value, otherwise, we keep it as is. 96 case Application.fetch_env(:logger, :level) do 97 {:ok, app_level} -> 98 level = Logger.Handler.elixir_level_to_erlang_level(app_level) 99 100 if erl_level != :notice and erl_level != level do 101 IO.warn( 102 "the level for Erlang's logger was set to #{inspect(erl_level)}, " <> 103 "but Elixir's logger was set to #{inspect(app_level)}. " <> 104 "Elixir's logger value will take higher precedence" 105 ) 106 end 107 108 :ok = :logger.set_primary_config(:level, level) 109 110 :error when erl_level == :notice -> 111 :ok = :logger.set_primary_config(:level, :debug) 112 113 :error -> 114 :ok 115 end 116 117 :ok = :logger.add_primary_filter(:process_disabled, {&Logger.Filter.process_disabled/2, []}) 118 :ok = :logger.add_handler(Logger, Logger.Handler, config) 119 primary_config 120 end 121 122 defp delete_erlang_handler() do 123 with {:ok, %{module: module} = config} <- :logger.get_handler_config(:default), 124 :ok <- :logger.remove_handler(:default) do 125 handler_config = {:default, module, config} 126 127 [handler_config] 128 else 129 _ -> [] 130 end 131 end 132 133 defp add_handlers(handlers) do 134 for handler <- handlers do 135 case handler do 136 {handler, module, config} -> 137 :logger.add_handler(handler, module, config) 138 139 {:primary, config} -> 140 :logger.set_primary_config(config) 141 end 142 end 143 144 :ok 145 end 146end 147