diff options
Diffstat (limited to 'src/ejabberd_logger.erl')
-rw-r--r-- | src/ejabberd_logger.erl | 275 |
1 files changed, 99 insertions, 176 deletions
diff --git a/src/ejabberd_logger.erl b/src/ejabberd_logger.erl index fa4151283..c1abd19b7 100644 --- a/src/ejabberd_logger.erl +++ b/src/ejabberd_logger.erl @@ -23,34 +23,30 @@ %%%------------------------------------------------------------------- -module(ejabberd_logger). +-compile({no_auto_import, [get/0]}). + +-include_lib("kernel/include/logger.hrl"). %% API --export([start/0, restart/0, reopen_log/0, rotate_log/0, get/0, set/1, - get_log_path/0]). +-export([start/0, get/0, set/1, get_log_path/0, flush/0]). +-export([convert_loglevel/1, loglevels/0]). +%% Deprecated functions +-export([restart/0, reopen_log/0, rotate_log/0]). +-deprecated([{restart, 0}, + {reopen_log, 0}, + {rotate_log, 0}]). +-type loglevel() :: none | logger:level(). --type loglevel() :: 0 | 1 | 2 | 3 | 4 | 5. --type lager_level() :: none | emergency | alert | critical | - error | warning | notice | info | debug. - --spec start() -> ok. --spec get_log_path() -> string(). --spec reopen_log() -> ok. --spec rotate_log() -> ok. --spec get() -> {loglevel(), atom(), string()}. --spec set(loglevel()) -> ok. +-define(is_loglevel(L), + ((L == none) or (L == emergency) or (L == alert) + or (L == critical) or (L == error) or (L == warning) + or (L == notice) or (L == info) or (L == debug))). %%%=================================================================== %%% API %%%=================================================================== -%% @doc Returns the full path to the ejabberd log file. -%% It first checks for application configuration parameter 'log_path'. -%% If not defined it checks the environment variable EJABBERD_LOG_PATH. -%% And if that one is neither defined, returns the default value: -%% "ejabberd.log" in current directory. -%% Note: If the directory where to place the ejabberd log file to not exist, -%% it is not created and no log file will be generated. -%% @spec () -> string() +-spec get_log_path() -> string(). get_log_path() -> case ejabberd_config:env_binary_to_list(ejabberd, log_path) of {ok, Path} -> @@ -64,186 +60,113 @@ get_log_path() -> end end. +-spec get_integer_env(atom(), T) -> T. get_integer_env(Name, Default) -> case application:get_env(ejabberd, Name) of - {ok, I} when is_integer(I), I>=0 -> + {ok, I} when is_integer(I), I>0 -> I; undefined -> Default; {ok, Junk} -> - error_logger:error_msg("wrong value for ~ts: ~p; " - "using ~p as a fallback~n", - [Name, Junk, Default]), - Default - end. -get_string_env(Name, Default) -> - case application:get_env(ejabberd, Name) of - {ok, L} when is_list(L) -> - L; - undefined -> - Default; - {ok, Junk} -> - error_logger:error_msg("wrong value for ~ts: ~p; " - "using ~p as a fallback~n", - [Name, Junk, Default]), + ?LOG_ERROR("Wrong value for ~ts: ~p; " + "using ~p as a fallback", + [Name, Junk, Default]), Default end. -%% @spec () -> ok +-spec loglevels() -> [loglevel(), ...]. +loglevels() -> + [none, emergency, alert, critical, error, warning, notice, info, debug]. + +-spec convert_loglevel(0..5) -> loglevel(). +convert_loglevel(0) -> none; +convert_loglevel(1) -> critical; +convert_loglevel(2) -> error; +convert_loglevel(3) -> warning; +convert_loglevel(4) -> info; +convert_loglevel(5) -> debug. + +-spec start() -> ok. start() -> - start(4). + start(info). -spec start(loglevel()) -> ok. start(Level) -> - LLevel = get_lager_loglevel(Level), - StartedApps = application:which_applications(5000), - case lists:keyfind(logger, 1, StartedApps) of - %% Elixir logger is started. We assume everything is in place - %% to use lager to Elixir logger bridge. - {logger, _, _} -> - error_logger:info_msg("Ignoring ejabberd logger options, using Elixir Logger.", []), - %% Do not start lager, we rely on Elixir Logger - do_start_for_logger(LLevel); - _ -> - do_start(LLevel) - end. - -do_start_for_logger(Level) -> - application:load(sasl), - application:set_env(sasl, sasl_error_logger, false), - application:load(lager), - application:set_env(lager, error_logger_redirect, false), - application:set_env(lager, error_logger_whitelist, ['Elixir.Logger.ErrorHandler']), - application:set_env(lager, crash_log, false), - application:set_env(lager, handlers, [{elixir_logger_backend, [{level, Level}]}]), - ejabberd:start_app(lager), - ok. - --spec do_start(atom()) -> ok. -do_start(Level) -> - application:load(sasl), - application:set_env(sasl, sasl_error_logger, false), - application:load(lager), - ConsoleLog = get_log_path(), - Dir = filename:dirname(ConsoleLog), + EjabberdLog = get_log_path(), + Dir = filename:dirname(EjabberdLog), ErrorLog = filename:join([Dir, "error.log"]), - CrashLog = filename:join([Dir, "crash.log"]), - LogRotateDate = get_string_env(log_rotate_date, ""), LogRotateSize = get_integer_env(log_rotate_size, 10*1024*1024), LogRotateCount = get_integer_env(log_rotate_count, 1), - LogRateLimit = get_integer_env(log_rate_limit, 100), - ConsoleLevel = case get_lager_version() >= "3.6.0" of - true -> [{level, Level}]; - false -> Level - end, - application:set_env(lager, error_logger_hwm, LogRateLimit), - application:set_env( - lager, handlers, - [{lager_console_backend, ConsoleLevel}, - {lager_file_backend, [{file, ConsoleLog}, {level, Level}, {date, LogRotateDate}, - {count, LogRotateCount}, {size, LogRotateSize}]}, - {lager_file_backend, [{file, ErrorLog}, {level, error}, {date, LogRotateDate}, - {count, LogRotateCount}, {size, LogRotateSize}]}]), - application:set_env(lager, crash_log, CrashLog), - application:set_env(lager, crash_log_date, LogRotateDate), - application:set_env(lager, crash_log_size, LogRotateSize), - application:set_env(lager, crash_log_count, LogRotateCount), - ejabberd:start_app(lager), - lists:foreach(fun(Handler) -> - lager:set_loghwm(Handler, LogRateLimit) - end, gen_event:which_handlers(lager_event)). + Config = #{max_no_bytes => LogRotateSize, + max_no_files => LogRotateCount, + filesync_repeat_interval => no_repeat, + sync_mode_qlen => 1000, + drop_mode_qlen => 1000, + flush_qlen => 5000}, + FmtConfig = #{legacy_header => false, + time_designator => $ , + max_size => 100*1024, + single_line => false}, + FileFmtConfig = FmtConfig#{template => file_template()}, + ConsoleFmtConfig = FmtConfig#{template => console_template()}, + logger:set_primary_config(level, Level), + logger:add_primary_filter(progress_report, + {fun logger_filters:progress/2, stop}), + logger:update_formatter_config(default, ConsoleFmtConfig), + logger:add_handler(ejabberd_log, logger_std_h, + #{level => all, + config => Config#{file => EjabberdLog}, + formatter => {logger_formatter, FileFmtConfig}}), + logger:add_handler(error_log, logger_std_h, + #{level => error, + config => Config#{file => ErrorLog}, + formatter => {logger_formatter, FileFmtConfig}}), + ok. restart() -> - Level = ejabberd_option:loglevel(), - application:stop(lager), - start(Level). + ok. + +console_template() -> + [time, " [", level, "] ", msg, io_lib:nl()]. + +file_template() -> + [time, " [", level, "] ", pid, + {mfa, ["@", mfa, {line, [":", line], []}], []}, " ", msg, io_lib:nl()]. -%% @spec () -> ok reopen_log() -> - %% Lager detects external log rotation automatically. ok. -%% @spec () -> ok rotate_log() -> - catch lager_crash_log ! rotate, - lists:foreach( - fun({lager_file_backend, File}) -> - whereis(lager_event) ! {rotate, File}; - (_) -> - ok - end, gen_event:which_handlers(lager_event)). + ok. -%% @spec () -> {loglevel(), atom(), string()} +-spec get() -> loglevel(). get() -> - case get_lager_loglevel() of - none -> {0, no_log, "No log"}; - emergency -> {1, critical, "Critical"}; - alert -> {1, critical, "Critical"}; - critical -> {1, critical, "Critical"}; - error -> {2, error, "Error"}; - warning -> {3, warning, "Warning"}; - notice -> {3, warning, "Warning"}; - info -> {4, info, "Info"}; - debug -> {5, debug, "Debug"} - end. - -set(LogLevel) when is_integer(LogLevel) -> - LagerLogLevel = get_lager_loglevel(LogLevel), - case get_lager_loglevel() of - LagerLogLevel -> - ok; - _ -> - ConsoleLog = get_log_path(), - lists:foreach( - fun({lager_file_backend, File} = H) when File == ConsoleLog -> - lager:set_loglevel(H, LagerLogLevel); - (lager_console_backend = H) -> - lager:set_loglevel(H, LagerLogLevel); - (elixir_logger_backend = H) -> - lager:set_loglevel(H, LagerLogLevel); - (_) -> - ok - end, get_lager_handlers()) - end, - case LogLevel of - 5 -> xmpp:set_config([{debug, true}]); - _ -> xmpp:set_config([{debug, false}]) - end. - -get_lager_loglevel() -> - Handlers = get_lager_handlers(), - lists:foldl(fun(lager_console_backend, _Acc) -> - lager:get_loglevel(lager_console_backend); - (elixir_logger_backend, _Acc) -> - lager:get_loglevel(elixir_logger_backend); - (_, Acc) -> - Acc - end, - none, Handlers). - --spec get_lager_loglevel(loglevel()) -> lager_level(). -get_lager_loglevel(LogLevel) -> - case LogLevel of - 0 -> none; - 1 -> critical; - 2 -> error; - 3 -> warning; - 4 -> info; - 5 -> debug - end. - -get_lager_handlers() -> - case catch gen_event:which_handlers(lager_event) of - {'EXIT',noproc} -> - []; - Result -> - Result + #{level := Level} = logger:get_primary_config(), + Level. + +-spec set(0..5 | loglevel()) -> ok. +set(N) when is_integer(N), N>=0, N=<5 -> + set(convert_loglevel(N)); +set(Level) when ?is_loglevel(Level) -> + case get() of + Level -> ok; + PrevLevel -> + ?LOG_NOTICE("Changing loglevel from '~s' to '~s'", + [PrevLevel, Level]), + logger:set_primary_config(level, Level), + case Level of + debug -> xmpp:set_config([{debug, true}]); + _ -> xmpp:set_config([{debug, false}]) + end end. --spec get_lager_version() -> string(). -get_lager_version() -> - Apps = application:loaded_applications(), - case lists:keyfind(lager, 1, Apps) of - {_, _, Vsn} -> Vsn; - false -> "0.0.0" - end. +-spec flush() -> ok. +flush() -> + lists:foreach( + fun(#{id := HandlerId, module := logger_std_h}) -> + logger_std_h:filesync(HandlerId); + (#{id := HandlerId, module := logger_disk_log_h}) -> + logger_disk_log_h:filesync(HandlerId); + (_) -> + ok + end, logger:get_handler_config()). |