Projects
Kolab:Winterfell
erlang-lager
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 3
View file
erlang-lager.spec
Changed
@@ -7,7 +7,7 @@ %global debug_package %{nil} Name: erlang-%{realname} -Version: 2.1.0 +Version: 3.1.0 Release: 1%{?dist} Summary: A logging framework for Erlang/OTP Group: Development/Languages @@ -18,9 +18,6 @@ %endif Source0: https://github.com/%{upstream}/%{realname}/archive/%{version}/%{realname}-%{version}.tar.gz -Patch1: lager-2.1.0-tmpfs.patch -Patch2: lager-2.1.0-test-noproc.patch - BuildRequires: erlang-rebar BuildRequires: erlang-goldrush >= 0.1.6 Requires: erlang-compiler%{?_isa} @@ -44,8 +41,6 @@ %prep %setup -q -n %{realname}-%{version} -%patch1 -p1 -%patch2 -p1 %build rebar compile -v
View file
lager-2.1.0-test-noproc.patch
Deleted
@@ -1,12 +0,0 @@ -Only in lager-2.1.0/: .eunit -diff -ur lager-2.1.0.1.tmpfs/test/lager_test_backend.erl lager-2.1.0/test/lager_test_backend.erl ---- lager-2.1.0.1.tmpfs/test/lager_test_backend.erl 2014-11-03 17:57:48.000000000 +0100 -+++ lager-2.1.0/test/lager_test_backend.erl 2015-05-17 14:53:04.953873200 +0200 -@@ -651,7 +651,6 @@ - TestBody("bad arg1",badarg1,"gen_server crash terminated with reason: bad argument in crash:handle_call/3"), - TestBody("bad arg2",badarg2,"gen_server crash terminated with reason: bad argument in call to erlang:iolist_to_binary([\"foo\",bar]) in crash:handle_call/3"), - TestBody("bad record",badrecord,"gen_server crash terminated with reason: bad record state in crash:handle_call/3"), -- TestBody("noproc",noproc,"gen_server crash terminated with reason: no such process or port in call to gen_event:call(foo, bar, baz)"), - TestBody("badfun",badfun,"gen_server crash terminated with reason: bad function booger in crash:handle_call/3") - ] - }.
View file
lager-2.1.0-tmpfs.patch
Deleted
@@ -1,35 +0,0 @@ -Only in lager-2.1.0: deps -Only in lager-2.1.0: ebin -diff -ur lager-2.1.0.orig/rebar.config lager-2.1.0/rebar.config ---- lager-2.1.0.orig/rebar.config 2014-11-03 17:57:48.000000000 +0100 -+++ lager-2.1.0/rebar.config 2015-05-15 16:58:51.418877768 +0200 -@@ -1,7 +1,7 @@ - {erl_opts, [debug_info, warn_untyped_record]}. - {erl_first_files, ["src/lager_util.erl"]}. - {deps, [ -- {goldrush, "0\.1\.6", -+ {goldrush, "0.1.6", - {git, "git://github.com/DeadZen/goldrush.git", {tag, "0.1.6"}}} - ]}. - -diff -ur lager-2.1.0.orig/src/lager_file_backend.erl lager-2.1.0/src/lager_file_backend.erl ---- lager-2.1.0.orig/src/lager_file_backend.erl 2014-11-03 17:57:48.000000000 +0100 -+++ lager-2.1.0/src/lager_file_backend.erl 2015-05-17 14:13:12.005066053 +0200 -@@ -706,17 +706,6 @@ - {ok, Bin3} = file:read_file("foo.log"), - ?assertMatch([_, _, "[error]", _, "Test message\n"], re:split(Bin3, " ", [{return, list}, {parts, 5}])) - end -- }, -- {"tracing with options should work", -- fun() -> -- file:delete("foo.log"), -- {ok, _} = lager:trace_file("foo.log", [{module, ?MODULE}], [{size, 20}, {check_interval, 1}]), -- lager:error("Test message"), -- ?assertNot(filelib:is_regular("foo.log.0")), -- lager:error("Test message"), -- timer:sleep(10), -- ?assert(filelib:is_regular("foo.log.0")) -- end - } - ] - }.
View file
debian.changelog
Changed
@@ -1,3 +1,9 @@ +erlang-lager (3.1.0-0~kolab1) unstable; urgency=medium + + * Bump version to 3.1.0. + + -- Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> Wed, 16 Mar 2016 21:39:31 +0100 + erlang-lager (2.1.0-1~kolab1) unstable; urgency=medium * Bump version to 2.1.0.
View file
debian.series
Changed
@@ -1,2 +0,0 @@ -lager-2.1.0-tmpfs.patch -lager-2.1.0-test-noproc.patch
View file
erlang-lager.dsc
Changed
@@ -2,7 +2,7 @@ Source: erlang-lager Binary: erlang-lager Architecture: any -Version: 2.1.0-1~kolab1 +Version: 3.1.0-0~kolab1 Maintainer: Philipp Huebner <debalance@debian.org> Uploaders: Christoph Erhardt <kolab@sicherha.de> Homepage: https://github.com/basho/lager @@ -11,5 +11,5 @@ Package-List: erlang-lager deb libs optional Files: - 00000000000000000000000000000000 0 lager_2.1.0.tar.gz + 00000000000000000000000000000000 0 lager-3.1.0.tar.gz 00000000000000000000000000000000 0 debian.tar.gz
View file
lager-2.1.0.tar.gz/README.md -> lager-3.1.0.tar.gz/README.md
Changed
@@ -13,12 +13,14 @@ alert, emergency) * Logger calls are transformed using a parse transform to allow capturing Module/Function/Line/Pid information -* When no handler is consuming a log level (eg. debug) no event is even sent +* When no handler is consuming a log level (eg. debug) no event is sent to the log handler * Supports multiple backends, including console and file. +* Supports multiple sinks * Rewrites common OTP error messages into more readable messages * Support for pretty printing records encountered at compile time * Tolerant in the face of large or many log messages, won't out of memory the node +* Optional feature to bypass log size truncation ("unsafe") * Supports internal time and date based rotation, as well as external rotation tools * Syslog style log level comparison flags * Colored terminal output (requires R16+) @@ -27,8 +29,8 @@ Usage ----- To use lager in your application, you need to define it as a rebar dep or have -some other way of including it in erlang's path. You can then add the -following option to the erlang compiler flags +some other way of including it in Erlang's path. You can then add the +following option to the erlang compiler flags: ```erlang {parse_transform, lager_transform} @@ -42,7 +44,7 @@ ``` Before logging any messages, you'll need to start the lager application. The -lager module's start function takes care of loading and starting any dependencies +lager module's `start` function takes care of loading and starting any dependencies lager requires. ```erlang @@ -68,7 +70,7 @@ lager:warning("Some message with a term: ~p", [Term]) ``` -The general form is lager:Severity() where Severity is one of the log levels +The general form is `lager:Severity()` where `Severity` is one of the log levels mentioned above. Configuration @@ -78,6 +80,7 @@ ```erlang {lager, [ + {log_root, "/var/log/hello"}, {handlers, [ {lager_console_backend, info}, {lager_file_backend, [{file, "error.log"}, {level, error}]}, @@ -86,13 +89,93 @@ ]}. ``` +```log_root``` variable is optional, by default file paths are relative to CWD. + The available configuration options for each backend are listed in their module's documentation. +Sinks +----- +Lager has traditionally supported a single sink (implemented as a +`gen_event` manager) named `lager_event` to which all backends were +connected. + +Lager now supports extra sinks; each sink can have different +sync/async message thresholds and different backends. + +### Sink configuration + +To use multiple sinks (beyond the built-in sink of lager and lager_event), you +need to: + +1. Setup rebar.config +2. Configure the backends in app.config + +#### Names + +Each sink has two names: one atom to be used like a module name for +sending messages, and that atom with `_lager_event` appended for backend +configuration. + +This reflects the legacy behavior: `lager:info` (or `critical`, or +`debug`, etc) is a way of sending a message to a sink named +`lager_event`. Now developers can invoke `audit:info` or +`myCompanyName:debug` so long as the corresponding `audit_lager_event` or +`myCompanyName_lager_event` sinks are configured. + +#### rebar.config + +In `rebar.config` for the project that requires lager, include a list +of sink names (without the `_lager_event` suffix) in `erl_opts`: + +`{lager_extra_sinks, [audit]}` + +#### Runtime requirements + +To be useful, sinks must be configured at runtime with backends. + +In `app.config` for the project that requires lager, for example, +extend the lager configuration to include an `extra_sinks` tuple with +backends (aka "handlers") and optionally `async_threshold` and +`async_threshold_window` values (see **Overload Protection** +below). If async values are not configured, no overload protection +will be applied on that sink. + +```erlang +[{lager, [ + {log_root, "/tmp"}, + + %% Default handlers for lager/lager_event + {handlers, [ + {lager_console_backend, info}, + {lager_file_backend, [{file, "error.log"}, {level, error}]}, + {lager_file_backend, [{file, "console.log"}, {level, info}]} + ]}, + + %% Any other sinks + {extra_sinks, + [ + {audit_lager_event, + [{handlers, + [{lager_file_backend, + [{file, "sink1.log"}, + {level, info} + ] + }] + }, + {async_threshold, 500}, + {async_threshold_window, 50}] + }] + } + ] + } +]. +``` + Custom Formatting ----------------- All loggers have a default formatting that can be overriden. A formatter is any module that -exports format(#lager_log_message{},Config#any()). It is specified as part of the configuration +exports `format(#lager_log_message{},Config#any())`. It is specified as part of the configuration for the backend: ```erlang @@ -106,49 +189,73 @@ ]}. ``` -Included is lager_default_formatter. This provides a generic, default formatting for log messages using a "semi-iolist" -as configuration. Any iolist allowed elements in the configuration are printed verbatim. Atoms in the configuration -are treated as metadata properties and extracted from the log message. -The metadata properties date,time, message, and severity will always exist. -The properties pid, file, line, module, function, and node will always exist if the parser transform is used. +Included is `lager_default_formatter`. This provides a generic, default formatting for log messages using a structure similar to Erlang's [iolist](http://learnyousomeerlang.com/buckets-of-sockets#io-lists) which we call "semi-iolist": -``` -["Foo"] -> "Foo", regardless of message content. -[message] -> The content of the logged message, alone. -[{pid,"Unknown Pid"}] -> "<?.?.?>" if pid is in the metadata, "Unknown Pid" if not. -[{pid, ["My pid is ", pid], "Unknown Pid"}] -> if pid is in the metadata print "My pid is <?.?.?>", otherwise print "Unknown Pid" -``` +* Any traditional iolist elements in the configuration are printed verbatim. +* Atoms in the configuration are treated as placeholders for lager metadata and extracted from the log message. + * The placeholders `date`, `time`, `message`, `sev` and `severity` will always exist. + * `sev` is an abbreviated severity which is interpreted as a capitalized single letter encoding of the severity level + (e.g. `'debug'` -> `$D`) + * The placeholders `pid`, `file`, `line`, `module`, `function`, and `node` will always exist if the parse transform is used. + * Applications can define their own metadata placeholder. + * A tuple of `{atom(), semi-iolist()}` allows for a fallback for + the atom placeholder. If the value represented by the atom + cannot be found, the semi-iolist will be interpreted instead. + * A tuple of `{atom(), semi-iolist(), semi-iolist()}` represents a + conditional operator: if a value for the atom placeholder can be + found, the first semi-iolist will be output; otherwise, the + second will be used. -Optionally, a tuple of {atom(),semi-iolist()} -can be used. The atom will look up the property, but if not found it will use the semi-iolist() instead. These fallbacks -can be nested or refer to other properties. +Examples: ``` +["Foo"] -> "Foo", regardless of message content. +[message] -> The content of the logged message, alone. [{pid,"Unknown Pid"}] -> "<?.?.?>" if pid is in the metadata, "Unknown Pid" if not. -[{server,[$(,{pid,"Unknown Server"},$)]}}] -> user provided server metadata, otherwise "(<?.?.?>)", otherwise "(Unknown Server)" +[{pid, ["My pid is ", pid], ["Unknown Pid"]}] -> if pid is in the metadata print "My pid is <?.?.?>", otherwise print "Unknown Pid" +[{server,{pid, ["(", pid, ")"], ["(Unknown Server)"]}}] -> user provided server metadata, otherwise "(<?.?.?>)", otherwise "(Unknown Server)" ``` Error logger integration ------------------------ -Lager is also supplied with a error_logger handler module that translates +Lager is also supplied with a `error_logger` handler module that translates traditional erlang error messages into a friendlier format and sends them into lager itself to be treated like a regular lager log call. To disable this, set
View file
lager-2.1.0.tar.gz/include/lager.hrl -> lager-3.1.0.tar.gz/include/lager.hrl
Changed
@@ -17,10 +17,18 @@ -define(DEFAULT_TRUNCATION, 4096). -define(DEFAULT_TRACER, lager_default_tracer). +-define(DEFAULT_SINK, lager_event). +-define(ERROR_LOGGER_SINK, error_logger_lager_event). + -define(LEVELS, [debug, info, notice, warning, error, critical, alert, emergency, none]). +%% Use of these "functions" means that the argument list will not be +%% truncated for safety +-define(LEVELS_UNSAFE, + [{debug_unsafe, debug}, {info_unsafe, info}, {notice_unsafe, notice}, {warning_unsafe, warning}, {error_unsafe, error}, {critical_unsafe, critical}, {alert_unsafe, alert}, {emergency_unsafe, emergency}]). + -define(DEBUG, 128). -define(INFO, 64). -define(NOTICE, 32). @@ -55,6 +63,9 @@ ?EMERGENCY -> emergency end). +-define(SHOULD_LOG(Sink, Level), + (lager_util:level_to_num(Level) band element(1, lager_config:get({Sink, loglevel}, {?LOG_NONE, []}))) /= 0). + -define(SHOULD_LOG(Level), (lager_util:level_to_num(Level) band element(1, lager_config:get(loglevel, {?LOG_NONE, []}))) /= 0). @@ -63,7 +74,7 @@ Level, [{pid,Pid},{line,?LINE},{file,?FILE},{module,?MODULE}], [])} - )). + )). %% FOR INTERNAL USE ONLY %% internal non-blocking logging call @@ -100,3 +111,15 @@ end)). -endif. +-record(lager_shaper, { + %% how many messages per second we try to deliver + hwm = undefined :: 'undefined' | pos_integer(), + %% how many messages we've received this second + mps = 0 :: non_neg_integer(), + %% the current second + lasttime = os:timestamp() :: erlang:timestamp(), + %% count of dropped messages this second + dropped = 0 :: non_neg_integer() + }). + +-type lager_shaper() :: #lager_shaper{}.
View file
lager-2.1.0.tar.gz/rebar.config -> lager-3.1.0.tar.gz/rebar.config
Changed
@@ -1,9 +1,51 @@ -{erl_opts, [debug_info, warn_untyped_record]}. +%% -*- erlang -*- +%% ------------------------------------------------------------------- +%% +%% Copyright (c) 2011-2015 Basho Technologies, Inc. +%% +%% This file is provided to you under the Apache License, +%% Version 2.0 (the "License"); you may not use this file +%% except in compliance with the License. You may obtain +%% a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, +%% software distributed under the License is distributed on an +%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%% KIND, either express or implied. See the License for the +%% specific language governing permissions and limitations +%% under the License. +%% +%% ------------------------------------------------------------------- + +{erl_opts, [ + {lager_extra_sinks, ['__lager_test_sink']}, + debug_info, + report, + verbose, + warn_deprecated_function, + warn_deprecated_type, + warn_export_all, + warn_export_vars, + warn_obsolete_guard, + warn_untyped_record, + warn_unused_import + % do NOT include warnings_as_errors, as rebar includes these options + % when compiling for eunit, and at least one test module has code that + % is deliberatly broken and will generate an un-maskable warning +]}. + {erl_first_files, ["src/lager_util.erl"]}. + +{eunit_opts, [verbose]}. +{eunit_compile_opts, [ + nowarn_untyped_record, + nowarn_export_all +]}. {deps, [ - {goldrush, "0\.1\.6", - {git, "git://github.com/DeadZen/goldrush.git", {tag, "0.1.6"}}} - ]}. + {goldrush, ".*", {git, "git://github.com/DeadZen/goldrush.git", {tag, "0.1.8"}}} +]}. {xref_checks, []}. {xref_queries, [{"(XC - UC) || (XU - X - B - lager_default_tracer : Mod - erlang:\"(is_map|map_size)\"/1 - maps:to_list/1)", []}]}.
View file
lager-2.1.0.tar.gz/src/error_logger_lager_h.erl -> lager-3.1.0.tar.gz/src/error_logger_lager_h.erl
Changed
@@ -1,4 +1,4 @@ -%% Copyright (c) 2011-2012 Basho Technologies, Inc. All Rights Reserved. +%% Copyright (c) 2011-2015 Basho Technologies, Inc. All Rights Reserved. %% %% This file is provided to you under the Apache License, %% Version 2.0 (the "License"); you may not use this file @@ -31,31 +31,28 @@ -export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2, code_change/3]). --export([format_reason/1]). - --record(state, { - %% how many messages per second we try to deliver - hwm = undefined :: 'undefined' | pos_integer(), - %% how many messages we've received this second - mps = 0 :: non_neg_integer(), - %% the current second - lasttime = os:timestamp() :: erlang:timestamp(), - %% count of dropped messages this second - dropped = 0 :: non_neg_integer() +-export([format_reason/1, format_mfa/1, format_args/3]). + +-record(state, { + sink :: atom(), + shaper :: lager_shaper(), + %% group leader strategy + groupleader_strategy :: handle | ignore | mirror, + raw :: boolean() }). --define(LOGMSG(Level, Pid, Msg), - case ?SHOULD_LOG(Level) of +-define(LOGMSG(Sink, Level, Pid, Msg), + case ?SHOULD_LOG(Sink, Level) of true -> - _ =lager:log(Level, Pid, Msg), + _ =lager:log(Sink, Level, Pid, Msg, []), ok; _ -> ok end). --define(LOGFMT(Level, Pid, Fmt, Args), - case ?SHOULD_LOG(Level) of +-define(LOGFMT(Sink, Level, Pid, Fmt, Args), + case ?SHOULD_LOG(Sink, Level) of true -> - _ = lager:log(Level, Pid, Fmt, Args), + _ = lager:log(Sink, Level, Pid, Fmt, Args), ok; _ -> ok end). @@ -74,20 +71,29 @@ gen_event:call(error_logger, ?MODULE, {set_high_water, N}, infinity). -spec init(any()) -> {ok, #state{}}. -init([HighWaterMark]) -> - {ok, #state{hwm=HighWaterMark}}. - -handle_call({set_high_water, N}, State) -> - {ok, ok, State#state{hwm = N}}; +init([HighWaterMark, GlStrategy]) -> + Shaper = #lager_shaper{hwm=HighWaterMark}, + Raw = application:get_env(lager, error_logger_format_raw, false), + Sink = configured_sink(), + {ok, #state{sink=Sink, shaper=Shaper, groupleader_strategy=GlStrategy, raw=Raw}}. + +handle_call({set_high_water, N}, #state{shaper=Shaper} = State) -> + NewShaper = Shaper#lager_shaper{hwm=N}, + {ok, ok, State#state{shaper = NewShaper}}; handle_call(_Request, State) -> {ok, unknown_call, State}. -handle_event(Event, State) -> - case check_hwm(State) of - {true, NewState} -> - log_event(Event, NewState); - {false, NewState} -> - {ok, NewState} +handle_event(Event, #state{sink=Sink, shaper=Shaper} = State) -> + case lager_util:check_hwm(Shaper) of + {true, 0, NewShaper} -> + eval_gl(Event, State#state{shaper=NewShaper}); + {true, Drop, #lager_shaper{hwm=Hwm} = NewShaper} when Drop > 0 -> + ?LOGFMT(Sink, warning, self(), + "lager_error_logger_h dropped ~p messages in the last second that exceeded the limit of ~p messages/sec", + [Drop, Hwm]), + eval_gl(Event, State#state{shaper=NewShaper}); + {false, _, NewShaper} -> + {ok, State#state{shaper=NewShaper}} end. handle_info(_Info, State) -> @@ -96,94 +102,96 @@ terminate(_Reason, _State) -> ok. + +code_change(_OldVsn, {state, Shaper, GLStrategy}, _Extra) -> + Raw = application:get_env(lager, error_logger_format_raw, false), + {ok, #state{ + sink=configured_sink(), + shaper=Shaper, + groupleader_strategy=GLStrategy, + raw=Raw + }}; +code_change(_OldVsn, {state, Sink, Shaper, GLS}, _Extra) -> + Raw = application:get_env(lager, error_logger_format_raw, false), + {ok, #state{sink=Sink, shaper=Shaper, groupleader_strategy=GLS, raw=Raw}}; code_change(_OldVsn, State, _Extra) -> {ok, State}. %% internal functions -check_hwm(State = #state{hwm = undefined}) -> - {true, State}; -check_hwm(State = #state{mps = Mps, hwm = Hwm}) when Mps < Hwm -> - %% haven't hit high water mark yet, just log it - {true, State#state{mps=Mps+1}}; -check_hwm(State = #state{hwm = Hwm, lasttime = Last, dropped = Drop}) -> - %% are we still in the same second? - {M, S, _} = Now = os:timestamp(), - case Last of - {M, S, _} -> - %% still in same second, but have exceeded the high water mark - NewDrops = discard_messages(Now, 0), - {false, State#state{dropped=Drop+NewDrops}}; - _ -> - %% different second, reset all counters and allow it - case Drop > 0 of - true -> - ?LOGFMT(warning, self(), "lager_error_logger_h dropped ~p messages in the last second that exceeded the limit of ~p messages/sec", - [Drop, Hwm]); - false -> - ok - end, - {true, State#state{dropped = 0, mps=1, lasttime = Now}} +configured_sink() -> + case proplists:get_value(?ERROR_LOGGER_SINK, application:get_env(lager, extra_sinks, [])) of + undefined -> ?DEFAULT_SINK; + _ -> ?ERROR_LOGGER_SINK end. -discard_messages(Second, Count) -> - {M, S, _} = os:timestamp(), - case Second of - {M, S, _} -> - receive - %% we only discard gen_event notifications, because - %% otherwise we might discard gen_event internal - %% messages, such as trapped EXITs - {notify, _Event} -> - discard_messages(Second, Count+1); - {_From, _Tag, {sync_notify, _Event}} -> - discard_messages(Second, Count+1) - after 0 -> - Count - end; - _ -> - Count - end. +eval_gl(Event, #state{groupleader_strategy=GlStrategy0}=State) when is_pid(element(2, Event)) -> + case element(2, Event) of + GL when node(GL) =/= node(), GlStrategy0 =:= ignore -> + gen_event:notify({error_logger, node(GL)}, Event), + {ok, State}; + GL when node(GL) =/= node(), GlStrategy0 =:= mirror -> + gen_event:notify({error_logger, node(GL)}, Event), + log_event(Event, State); + _ -> + log_event(Event, State) + end; +eval_gl(Event, State) -> + log_event(Event, State). -log_event(Event, State) -> +log_event(Event, #state{sink=Sink} = State) -> case Event of {error, _GL, {Pid, Fmt, Args}} -> - case Fmt of - "** Generic server "++_ -> + FormatRaw = State#state.raw, + case {FormatRaw, Fmt} of + {false, "** Generic server "++_} -> %% gen_server terminate [Name, _Msg, _State, Reason] = Args, ?CRASH_LOG(Event), - ?LOGFMT(error, Pid, "gen_server ~w terminated with reason: ~s", + ?LOGFMT(Sink, error, Pid, "gen_server ~w terminated with reason: ~s", [Name, format_reason(Reason)]); - "** State machine "++_ -> + {false, "** State machine "++_} -> %% gen_fsm terminate [Name, _Msg, StateName, _StateData, Reason] = Args, ?CRASH_LOG(Event), - ?LOGFMT(error, Pid, "gen_fsm ~w in state ~w terminated with reason: ~s", + ?LOGFMT(Sink, error, Pid, "gen_fsm ~w in state ~w terminated with reason: ~s", [Name, StateName, format_reason(Reason)]); - "** gen_event handler"++_ -> + {false, "** gen_event handler"++_} ->
View file
lager-2.1.0.tar.gz/src/lager.app.src -> lager-3.1.0.tar.gz/src/lager.app.src
Changed
@@ -3,7 +3,7 @@ {application, lager, [ {description, "Erlang logging framework"}, - {vsn, "2.1.0"}, + {vsn, "3.1.0"}, {modules, []}, {applications, [ kernel, @@ -13,9 +13,9 @@ {registered, [lager_sup, lager_event, lager_crash_log, lager_handler_watcher_sup]}, {mod, {lager_app, []}}, {env, [ - %% Note: application:start(lager) overwrites previously defined environment variables + %% Note: application:start(lager) overwrites previously defined environment variables %% thus declaration of default handlers is done at lager_app.erl - + %% What colors to use with what log levels {colored, false}, {colors, [ @@ -43,14 +43,18 @@ %% Number of rotated crash logs to keep, 0 means keep only the %% current one - default is 0 {crash_log_count, 5}, - %% Whether to redirect error_logger messages into lager - defaults to true + %% Whether to redirect error_logger messages into the default lager_event sink - defaults to true {error_logger_redirect, true}, %% How many messages per second to allow from error_logger before we start dropping them {error_logger_hwm, 50}, - %% How big the gen_event mailbox can get before it is switched into sync mode + %% How big the gen_event mailbox can get before it is + %% switched into sync mode. This value only applies to + %% the default sink; extra sinks can supply their own. {async_threshold, 20}, - %% Switch back to async mode, when gen_event mailbox size decrease from `async_threshold' - %% to async_threshold - async_threshold_window + %% Switch back to async mode, when gen_event mailbox size + %% decrease from `async_threshold' to async_threshold - + %% async_threshold_window. This value only applies to the + %% default sink; extra sinks can supply their own. {async_threshold_window, 5} ]} ]}.
View file
lager-2.1.0.tar.gz/src/lager.erl -> lager-3.1.0.tar.gz/src/lager.erl
Changed
@@ -21,17 +21,21 @@ -include("lager.hrl"). -define(LAGER_MD_KEY, '__lager_metadata'). +-define(TRACE_SINK, '__trace_sink'). +-define(ROTATE_TIMEOUT, 100000). %% API -export([start/0, - log/3, log/4, + log/3, log/4, log/5, + log_unsafe/4, md/0, md/1, + rotate_handler/1, rotate_handler/2, rotate_sink/1, rotate_all/0, trace/2, trace/3, trace_file/2, trace_file/3, trace_file/4, trace_console/1, trace_console/2, - clear_all_traces/0, stop_trace/1, status/0, - get_loglevel/1, set_loglevel/2, set_loglevel/3, get_loglevels/0, - update_loglevel_config/0, posix_error/1, - safe_format/3, safe_format_chop/3, dispatch_log/5, dispatch_log/9, - do_log/9, pr/2]). + list_all_sinks/0, clear_all_traces/0, stop_trace/1, stop_trace/3, status/0, + get_loglevel/1, get_loglevel/2, set_loglevel/2, set_loglevel/3, set_loglevel/4, get_loglevels/1, + update_loglevel_config/1, posix_error/1, set_loghwm/2, set_loghwm/3, set_loghwm/4, + safe_format/3, safe_format_chop/3, unsafe_format/2, dispatch_log/5, dispatch_log/7, dispatch_log/9, + do_log/9, do_log/10, do_log_unsafe/10, pr/2, pr/3, pr_stacktrace/1, pr_stacktrace/2]). -type log_level() :: debug | info | notice | warning | error | critical | alert | emergency. -type log_level_number() :: 0..7. @@ -81,51 +85,85 @@ md(_) -> erlang:error(badarg). --spec dispatch_log(log_level(), list(), string(), list() | none, pos_integer()) -> ok | {error, lager_not_running}. + +-spec dispatch_log(atom(), log_level(), list(), string(), list() | none, pos_integer(), safe | unsafe) -> ok | {error, lager_not_running} | {error, {sink_not_configured, atom()}}. %% this is the same check that the parse transform bakes into the module at compile time -dispatch_log(Severity, Metadata, Format, Args, Size) when is_atom(Severity)-> +%% see lager_transform (lines 173-216) +dispatch_log(Sink, Severity, Metadata, Format, Args, Size, Safety) when is_atom(Severity)-> SeverityAsInt=lager_util:level_to_num(Severity), - case {whereis(lager_event), lager_config:get(loglevel, {?LOG_NONE, []})} of - {undefined, _} -> - {error, lager_not_running}; - {Pid, {Level, Traces}} when (Level band SeverityAsInt) /= 0 orelse Traces /= [] -> - do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, Level, Traces, Pid); - _ -> - ok + case {whereis(Sink), whereis(?DEFAULT_SINK), lager_config:get({Sink, loglevel}, {?LOG_NONE, []})} of + {undefined, undefined, _} -> {error, lager_not_running}; + {undefined, _LagerEventPid0, _} -> {error, {sink_not_configured, Sink}}; + {SinkPid, _LagerEventPid1, {Level, Traces}} when Safety =:= safe andalso ( (Level band SeverityAsInt) /= 0 orelse Traces /= [] ) -> + do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, Level, Traces, Sink, SinkPid); + {SinkPid, _LagerEventPid1, {Level, Traces}} when Safety =:= unsafe andalso ( (Level band SeverityAsInt) /= 0 orelse Traces /= [] ) -> + do_log_unsafe(Severity, Metadata, Format, Args, Size, SeverityAsInt, Level, Traces, Sink, SinkPid); + _ -> ok end. %% @private Should only be called externally from code generated from the parse transform -do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, LevelThreshold, TraceFilters, Pid) when is_atom(Severity) -> - Destinations = case TraceFilters of +do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid) when is_atom(Severity) -> + FormatFun = fun() -> safe_format_chop(Format, Args, Size) end, + do_log_impl(Severity, Metadata, Format, Args, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid, FormatFun). + +do_log_impl(Severity, Metadata, Format, Args, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid, FormatFun) -> + {Destinations, TraceSinkPid} = case TraceFilters of [] -> - []; + {[], undefined}; _ -> - lager_util:check_traces(Metadata,SeverityAsInt,TraceFilters,[]) + {lager_util:check_traces(Metadata,SeverityAsInt,TraceFilters,[]), whereis(?TRACE_SINK)} end, case (LevelThreshold band SeverityAsInt) /= 0 orelse Destinations /= [] of true -> Msg = case Args of A when is_list(A) -> - safe_format_chop(Format,Args,Size); + FormatFun(); _ -> Format end, LagerMsg = lager_msg:new(Msg, Severity, Metadata, Destinations), - case lager_config:get(async, false) of + case lager_config:get({Sink, async}, false) of true -> - gen_event:notify(Pid, {log, LagerMsg}); + gen_event:notify(SinkPid, {log, LagerMsg}); false -> - gen_event:sync_notify(Pid, {log, LagerMsg}) + gen_event:sync_notify(SinkPid, {log, LagerMsg}) + end, + case TraceSinkPid /= undefined of + true -> + gen_event:notify(TraceSinkPid, {log, LagerMsg}); + false -> + ok end; false -> ok end. +%% @private Should only be called externally from code generated from the parse transform +%% Specifically, it would be level ++ `_unsafe' as in `info_unsafe'. +do_log_unsafe(Severity, Metadata, Format, Args, _Size, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid) when is_atom(Severity) -> + FormatFun = fun() -> unsafe_format(Format, Args) end, + do_log_impl(Severity, Metadata, Format, Args, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid, FormatFun). + + %% backwards compatible with beams compiled with lager 1.x dispatch_log(Severity, _Module, _Function, _Line, _Pid, Metadata, Format, Args, Size) -> dispatch_log(Severity, Metadata, Format, Args, Size). +%% backwards compatible with beams compiled with lager 2.x +dispatch_log(Severity, Metadata, Format, Args, Size) -> + dispatch_log(?DEFAULT_SINK, Severity, Metadata, Format, Args, Size, safe). + +%% backwards compatible with beams compiled with lager 2.x +do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, LevelThreshold, TraceFilters, SinkPid) -> + do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, + LevelThreshold, TraceFilters, ?DEFAULT_SINK, SinkPid). + + +%% TODO: +%% Consider making log2/4 that takes the Level, Pid and Message params of log/3 +%% along with a Sink param?? + %% @doc Manually log a message into lager without using the parse transform. -spec log(log_level(), pid() | atom() | [tuple(),...], list()) -> ok | {error, lager_not_running}. log(Level, Pid, Message) when is_pid(Pid); is_atom(Pid) -> @@ -140,6 +178,27 @@ log(Level, Metadata, Format, Args) when is_list(Metadata) -> dispatch_log(Level, Metadata, Format, Args, ?DEFAULT_TRUNCATION). +log_unsafe(Level, Metadata, Format, Args) when is_list(Metadata) -> + dispatch_log(?DEFAULT_SINK, Level, Metadata, Format, Args, ?DEFAULT_TRUNCATION, unsafe). + + +%% @doc Manually log a message into lager without using the parse transform. +-spec log(atom(), log_level(), pid() | atom() | [tuple(),...], string(), list()) -> ok | {error, lager_not_running}. +log(Sink, Level, Pid, Format, Args) when is_pid(Pid); is_atom(Pid) -> + dispatch_log(Sink, Level, [{pid,Pid}], Format, Args, ?DEFAULT_TRUNCATION, safe); +log(Sink, Level, Metadata, Format, Args) when is_list(Metadata) -> + dispatch_log(Sink, Level, Metadata, Format, Args, ?DEFAULT_TRUNCATION, safe). + +validate_trace_filters(Filters, Level, Backend) -> + Sink = proplists:get_value(sink, Filters, ?DEFAULT_SINK), + {Sink, + lager_util:validate_trace({ + proplists:delete(sink, Filters), + Level, + Backend + }) + }. + trace_file(File, Filter) -> trace_file(File, Filter, debug, []). @@ -148,34 +207,43 @@ trace_file(File, Filter, Options) when is_list(Options) -> trace_file(File, Filter, debug, Options). - + trace_file(File, Filter, Level, Options) -> - Trace0 = {Filter, Level, {lager_file_backend, File}}, - case lager_util:validate_trace(Trace0) of - {ok, Trace} -> - Handlers = gen_event:which_handlers(lager_event), + FileName = lager_util:expand_path(File), + case validate_trace_filters(Filter, Level, {lager_file_backend, FileName}) of + {Sink, {ok, Trace}} -> + Handlers = lager_config:global_get(handlers, []), %% check if this file backend is already installed - Res = case lists:member({lager_file_backend, File}, Handlers) of - false -> - %% install the handler - LogFileConfig = lists:keystore(level, 1, lists:keystore(file, 1, Options, {file, File}), {level, none}), - supervisor:start_child(lager_handler_watcher_sup, - [lager_event, {lager_file_backend, File}, LogFileConfig]); - _ -> - {ok, exists} + Res = case lists:keyfind({lager_file_backend, FileName}, 1, Handlers) of + false -> + %% install the handler + LogFileConfig = + lists:keystore(level, 1, + lists:keystore(file, 1, + Options, + {file, FileName}), + {level, none}), + HandlerInfo = + lager_app:start_handler(Sink, {lager_file_backend, FileName}, + LogFileConfig), + lager_config:global_set(handlers, [HandlerInfo|Handlers]), + {ok, installed}; + {_Watcher, _Handler, Sink} -> + {ok, exists}; + {_Watcher, _Handler, _OtherSink} ->
View file
lager-2.1.0.tar.gz/src/lager_app.erl -> lager-3.1.0.tar.gz/src/lager_app.erl
Changed
@@ -27,93 +27,204 @@ -endif. -export([start/0, start/2, + start_handler/3, stop/1]). +-define(FILENAMES, '__lager_file_backend_filenames'). +-define(THROTTLE, lager_backend_throttle). +-define(DEFAULT_HANDLER_CONF, + [{lager_console_backend, info}, + {lager_file_backend, + [{file, "log/error.log"}, {level, error}, + {size, 10485760}, {date, "$D0"}, {count, 5}] + }, + {lager_file_backend, + [{file, "log/console.log"}, {level, info}, + {size, 10485760}, {date, "$D0"}, {count, 5}] + } + ]). + start() -> application:start(lager). -start(_StartType, _StartArgs) -> - {ok, Pid} = lager_sup:start_link(), +start_throttle(Sink, Threshold, Window) -> + _ = supervisor:start_child(lager_handler_watcher_sup, + [Sink, ?THROTTLE, [Threshold, Window]]), + ok. +determine_async_behavior(_Sink, {ok, undefined}, _Window) -> + ok; +determine_async_behavior(_Sink, undefined, _Window) -> + ok; +determine_async_behavior(_Sink, {ok, Threshold}, _Window) when not is_integer(Threshold) orelse Threshold < 0 -> + error_logger:error_msg("Invalid value for 'async_threshold': ~p~n", + [Threshold]), + throw({error, bad_config}); +determine_async_behavior(Sink, {ok, Threshold}, undefined) -> + start_throttle(Sink, Threshold, erlang:trunc(Threshold * 0.2)); +determine_async_behavior(_Sink, {ok, Threshold}, {ok, Window}) when not is_integer(Window) orelse Window > Threshold orelse Window < 0 -> + error_logger:error_msg( + "Invalid value for 'async_threshold_window': ~p~n", [Window]), + throw({error, bad_config}); +determine_async_behavior(Sink, {ok, Threshold}, {ok, Window}) -> + start_throttle(Sink, Threshold, Window). - case application:get_env(lager, async_threshold) of - undefined -> - ok; - {ok, undefined} -> - undefined; - {ok, Threshold} when is_integer(Threshold), Threshold >= 0 -> - DefWindow = erlang:trunc(Threshold * 0.2), % maybe 0? - ThresholdWindow = - case application:get_env(lager, async_threshold_window) of +start_handlers(_Sink, undefined) -> + ok; +start_handlers(_Sink, Handlers) when not is_list(Handlers) -> + error_logger:error_msg( + "Invalid value for 'handlers' (must be list): ~p~n", [Handlers]), + throw({error, bad_config}); +start_handlers(Sink, Handlers) -> + %% handlers failing to start are handled in the handler_watcher + lager_config:global_set(handlers, + lager_config:global_get(handlers, []) ++ + lists:map(fun({Module, Config}) -> + check_handler_config(Module, Config), + start_handler(Sink, Module, Config); + (_) -> + throw({error, bad_config}) + end, + expand_handlers(Handlers))), + ok. + +start_handler(Sink, Module, Config) -> + {ok, Watcher} = supervisor:start_child(lager_handler_watcher_sup, + [Sink, Module, Config]), + {Module, Watcher, Sink}. + +check_handler_config({lager_file_backend, F}, Config) when is_list(Config) -> + Fs = case get(?FILENAMES) of + undefined -> ordsets:new(); + X -> X + end, + case ordsets:is_element(F, Fs) of + true -> + error_logger:error_msg( + "Cannot have same file (~p) in multiple file backends~n", [F]), + throw({error, bad_config}); + false -> + put(?FILENAMES, + ordsets:add_element(F, Fs)) + end, + ok; +check_handler_config(_Handler, Config) when is_list(Config) orelse is_atom(Config) -> + ok; +check_handler_config(Handler, _BadConfig) -> + throw({error, {bad_config, Handler}}). + +clean_up_config_checks() -> + erase(?FILENAMES). + +interpret_hwm(undefined) -> + undefined; +interpret_hwm({ok, undefined}) -> + undefined; +interpret_hwm({ok, HWM}) when not is_integer(HWM) orelse HWM < 0 -> + _ = lager:log(warning, self(), "Invalid error_logger high water mark: ~p, disabling", [HWM]), + undefined; +interpret_hwm({ok, HWM}) -> + HWM. + +start_error_logger_handler({ok, false}, _HWM, _Whitelist) -> + []; +start_error_logger_handler(_, HWM, undefined) -> + start_error_logger_handler(ignore_me, HWM, {ok, []}); +start_error_logger_handler(_, HWM, {ok, WhiteList}) -> + GlStrategy = case application:get_env(lager, error_logger_groupleader_strategy) of undefined -> - DefWindow; - {ok, Window} when is_integer(Window), Window < Threshold, Window >= 0 -> - Window; - {ok, BadWindow} -> + handle; + {ok, GlStrategy0} when + GlStrategy0 =:= handle; + GlStrategy0 =:= ignore; + GlStrategy0 =:= mirror -> + GlStrategy0; + {ok, BadGlStrategy} -> error_logger:error_msg( - "Invalid value for 'async_threshold_window': ~p~n", [BadWindow]), + "Invalid value for 'error_logger_groupleader_strategy': ~p~n", + [BadGlStrategy]), throw({error, bad_config}) end, - _ = supervisor:start_child(lager_handler_watcher_sup, - [lager_event, lager_backend_throttle, [Threshold, ThresholdWindow]]), - ok; - {ok, BadThreshold} -> - error_logger:error_msg("Invalid value for 'async_threshold': ~p~n", [BadThreshold]), - throw({error, bad_config}) - end, - Handlers = case application:get_env(lager, handlers) of - undefined -> - [{lager_console_backend, info}, - {lager_file_backend, [{file, "log/error.log"}, {level, error}, {size, 10485760}, {date, "$D0"}, {count, 5}]}, - {lager_file_backend, [{file, "log/console.log"}, {level, info}, {size, 10485760}, {date, "$D0"}, {count, 5}]}]; - {ok, Val} -> - Val - end, + case supervisor:start_child(lager_handler_watcher_sup, [error_logger, error_logger_lager_h, [HWM, GlStrategy]]) of + {ok, _} -> + [begin error_logger:delete_report_handler(X), X end || + X <- gen_event:which_handlers(error_logger) -- [error_logger_lager_h | WhiteList]]; + {error, _} -> + [] + end. - %% handlers failing to start are handled in the handler_watcher - _ = [supervisor:start_child(lager_handler_watcher_sup, [lager_event, Module, Config]) || - {Module, Config} <- expand_handlers(Handlers)], +%% `determine_async_behavior/3' is called with the results from either +%% `application:get_env/2' and `proplists:get_value/2'. Since +%% `application:get_env/2' wraps a successful retrieval in an `{ok, +%% Value}' tuple, do the same for the result from +%% `proplists:get_value/2'. +wrap_proplist_value(undefined) -> + undefined; +wrap_proplist_value(Value) -> + {ok, Value}. - ok = add_configured_traces(), +configure_sink(Sink, SinkDef) -> + lager_config:new_sink(Sink), + ChildId = lager_util:make_internal_sink_name(Sink), + _ = supervisor:start_child(lager_sup, + {ChildId, + {gen_event, start_link, + [{local, Sink}]}, + permanent, 5000, worker, dynamic}), + determine_async_behavior(Sink, + wrap_proplist_value( + proplists:get_value(async_threshold, SinkDef)), + wrap_proplist_value( + proplists:get_value(async_threshold_window, SinkDef)) + ), + start_handlers(Sink, + proplists:get_value(handlers, SinkDef, [])), - %% mask the messages we have no use for - lager:update_loglevel_config(), - - HighWaterMark = case application:get_env(lager, error_logger_hwm) of - {ok, undefined} -> - undefined; - {ok, HwmVal} when is_integer(HwmVal), HwmVal > 0 ->
View file
lager-2.1.0.tar.gz/src/lager_backend_throttle.erl -> lager-3.1.0.tar.gz/src/lager_backend_throttle.erl
Changed
@@ -29,15 +29,27 @@ -export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2, code_change/3]). +%% +%% Allow test code to verify that we're doing the needful. +-ifdef(TEST). +-define(ETS_TABLE, async_threshold_test). +-define(TOGGLE_SYNC(), test_increment(sync_toggled)). +-define(TOGGLE_ASYNC(), test_increment(async_toggled)). +-else. +-define(TOGGLE_SYNC(), true). +-define(TOGGLE_ASYNC(), true). +-endif. + -record(state, { + sink :: atom(), hwm :: non_neg_integer(), window_min :: non_neg_integer(), async = true :: boolean() }). -init([Hwm, Window]) -> - lager_config:set(async, true), - {ok, #state{hwm=Hwm, window_min=Hwm - Window}}. +init([{sink, Sink}, Hwm, Window]) -> + lager_config:set({Sink, async}, true), + {ok, #state{sink=Sink, hwm=Hwm, window_min=Hwm - Window}}. handle_call(get_loglevel, State) -> @@ -52,11 +64,13 @@ case {Len > State#state.hwm, Len < State#state.window_min, State#state.async} of {true, _, true} -> %% need to flip to sync mode - lager_config:set(async, false), + ?TOGGLE_SYNC(), + lager_config:set({State#state.sink, async}, false), {ok, State#state{async=false}}; {_, true, false} -> %% need to flip to async mode - lager_config:set(async, true), + ?TOGGLE_ASYNC(), + lager_config:set({State#state.sink, async}, true), {ok, State#state{async=true}}; _ -> %% nothing needs to change @@ -76,3 +90,16 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}. +-ifdef(TEST). +test_get(Key) -> + get_default(ets:lookup(?ETS_TABLE, Key)). + +test_increment(Key) -> + ets:insert(?ETS_TABLE, + {Key, test_get(Key) + 1}). + +get_default([]) -> + 0; +get_default([{_Key, Value}]) -> + Value. +-endif.
View file
lager-2.1.0.tar.gz/src/lager_common_test_backend.erl -> lager-3.1.0.tar.gz/src/lager_common_test_backend.erl
Changed
@@ -40,9 +40,15 @@ bounce(Level) -> _ = application:stop(lager), - lager:start(), - gen_event:add_handler(lager_event, lager_common_test_backend, [Level, false]), - %lager:set_loglevel(lager_common_test_backend, Level), + application:set_env(lager, suppress_application_start_stop, true), + application:set_env(lager, handlers, + [ + {lager_common_test_backend, [Level, false]} + ]), + ok = lager:start(), + %% we care more about getting all of our messages here than being + %% careful with the amount of memory that we're using. + error_logger_lager_h:set_high_water(100000), ok. -spec(init(integer()|atom()|[term()]) -> {ok, #state{}} | {error, atom()}).
View file
lager-2.1.0.tar.gz/src/lager_config.erl -> lager-3.1.0.tar.gz/src/lager_config.erl
Changed
@@ -20,9 +20,16 @@ -include("lager.hrl"). --export([new/0, get/1, get/2, set/2]). +-export([new/0, new_sink/1, get/1, get/2, set/2, + global_get/1, global_get/2, global_set/2]). -define(TBL, lager_config). +-define(GLOBAL, '_global'). + +%% For multiple sinks, the key is now the registered event name and the old key +%% as a tuple. +%% +%% {{lager_event, loglevel}, Value} instead of {loglevel, Value} new() -> %% set up the ETS configuration table @@ -33,32 +40,48 @@ error:badarg -> ?INT_LOG(warning, "Table ~p already exists", [?TBL]) end, + new_sink(?DEFAULT_SINK), + %% Need to be able to find the `lager_handler_watcher' for all handlers + ets:insert_new(?TBL, {{?GLOBAL, handlers}, []}), + ok. + +new_sink(Sink) -> %% use insert_new here so that if we're in an appup we don't mess anything up %% %% until lager is completely started, allow all messages to go through - ets:insert_new(?TBL, {loglevel, {element(2, lager_util:config_to_mask(debug)), []}}), - ok. + ets:insert_new(?TBL, {{Sink, loglevel}, {element(2, lager_util:config_to_mask(debug)), []}}). + +global_get(Key) -> + global_get(Key, undefined). + +global_get(Key, Default) -> + get({?GLOBAL, Key}, Default). +global_set(Key, Value) -> + set({?GLOBAL, Key}, Value). + +get({_Sink, _Key}=FullKey) -> + get(FullKey, undefined); get(Key) -> - case ets:lookup(?TBL, Key) of - [] -> - undefined; - [{Key, Res}] -> - Res - end. + get({?DEFAULT_SINK, Key}, undefined). -get(Key, Default) -> - try ?MODULE:get(Key) of - undefined -> +get({Sink, Key}, Default) -> + try + case ets:lookup(?TBL, {Sink, Key}) of + [] -> Default; - Res -> + [{{Sink, Key}, Res}] -> Res + end catch _:_ -> Default - end. + end; +get(Key, Default) -> + get({?DEFAULT_SINK, Key}, Default). +set({Sink, Key}, Value) -> + ets:insert(?TBL, {{Sink, Key}, Value}); set(Key, Value) -> - ets:insert(?TBL, {Key, Value}). - + set({?DEFAULT_SINK, Key}, Value).
View file
lager-2.1.0.tar.gz/src/lager_console_backend.erl -> lager-3.1.0.tar.gz/src/lager_console_backend.erl
Changed
@@ -38,6 +38,8 @@ -define(TERSE_FORMAT,[time, " ", color, "[", severity,"] ", message]). %% @private +init([Level]) when is_atom(Level) -> + init(Level); init([Level, true]) -> % for backwards compatibility init([Level,{lager_default_formatter,[{eol, eol()}]}]); init([Level,false]) -> % for backwards compatibility @@ -75,7 +77,6 @@ init(Level) -> init([Level,{lager_default_formatter,?TERSE_FORMAT ++ [eol()]}]). - %% @private handle_call(get_loglevel, #state{level=Level} = State) -> {ok, Level, State}; @@ -186,7 +187,7 @@ register(user, Pid), erlang:group_leader(Pid, whereis(lager_event)), gen_event:add_handler(lager_event, lager_console_backend, info), - lager_config:set(loglevel, {element(2, lager_util:config_to_mask(info)), []}), + lager_config:set({lager_event, loglevel}, {element(2, lager_util:config_to_mask(info)), []}), lager:log(info, self(), "Test message"), receive {io_request, From, ReplyAs, {put_chars, unicode, Msg}} -> @@ -206,7 +207,7 @@ register(user, Pid), erlang:group_leader(Pid, whereis(lager_event)), gen_event:add_handler(lager_event, lager_console_backend, [info, true]), - lager_config:set(loglevel, {element(2, lager_util:config_to_mask(info)), []}), + lager_config:set({lager_event, loglevel}, {element(2, lager_util:config_to_mask(info)), []}), lager:info("Test message"), PidStr = pid_to_list(self()), receive @@ -228,7 +229,7 @@ gen_event:add_handler(lager_event, lager_console_backend, [info, {lager_default_formatter, [date,"#",time,"#",severity,"#",node,"#",pid,"#", module,"#",function,"#",file,"#",line,"#",message,"\r\n"]}]), - lager_config:set(loglevel, {?INFO, []}), + lager_config:set({lager_event, loglevel}, {?INFO, []}), lager:info("Test message"), PidStr = pid_to_list(self()), NodeStr = atom_to_list(node()), @@ -251,7 +252,7 @@ register(user, Pid), gen_event:add_handler(lager_event, lager_console_backend, info), erlang:group_leader(Pid, whereis(lager_event)), - lager_config:set(loglevel, {element(2, lager_util:config_to_mask(info)), []}), + lager_config:set({lager_event, loglevel}, {element(2, lager_util:config_to_mask(info)), []}), lager:debug("Test message"), receive {io_request, From, ReplyAs, {put_chars, unicode, _Msg}} -> @@ -280,7 +281,7 @@ unregister(user), register(user, Pid), gen_event:add_handler(lager_event, lager_console_backend, info), - lager_config:set(loglevel, {element(2, lager_util:config_to_mask(info)), []}), + lager_config:set({lager_event, loglevel}, {element(2, lager_util:config_to_mask(info)), []}), erlang:group_leader(Pid, whereis(lager_event)), lager:debug("Test message"), receive @@ -319,7 +320,7 @@ unregister(user), register(user, Pid), gen_event:add_handler(lager_event, lager_console_backend, info), - lager_config:set(loglevel, {element(2, lager_util:config_to_mask(info)), []}), + lager_config:set({lager_event, loglevel}, {element(2, lager_util:config_to_mask(info)), []}), lager:set_loglevel(lager_console_backend, '!=info'), erlang:group_leader(Pid, whereis(lager_event)), lager:debug("Test message"), @@ -350,7 +351,7 @@ unregister(user), register(user, Pid), gen_event:add_handler(lager_event, lager_console_backend, info), - lager_config:set(loglevel, {element(2, lager_util:config_to_mask(info)), []}), + lager_config:set({lager_event, loglevel}, {element(2, lager_util:config_to_mask(info)), []}), lager:set_loglevel(lager_console_backend, '=debug'), erlang:group_leader(Pid, whereis(lager_event)), lager:debug("Test message"),
View file
lager-2.1.0.tar.gz/src/lager_crash_log.erl -> lager-3.1.0.tar.gz/src/lager_crash_log.erl
Changed
@@ -66,7 +66,8 @@ Date, Count], []). %% @private -init([Filename, MaxBytes, Size, Date, Count]) -> +init([RelFilename, MaxBytes, Size, Date, Count]) -> + Filename = lager_util:expand_path(RelFilename), case lager_util:open_logfile(Filename, false) of {ok, {FD, Inode, _}} -> schedule_rotation(Date),
View file
lager-2.1.0.tar.gz/src/lager_default_formatter.erl -> lager-3.1.0.tar.gz/src/lager_default_formatter.erl
Changed
@@ -40,7 +40,7 @@ %% or refer to other properties, if desired. You can also use a {atom, semi-iolist(), semi-iolist()} formatter, which %% acts like a ternary operator's true/false branches. %% -%% The metadata properties date,time, message, and severity will always exist. +%% The metadata properties date,time, message, severity, and sev will always exist. %% The properties pid, file, line, module, and function will always exist if the parser transform is used. %% %% Example: @@ -51,7 +51,7 @@ %% %% `[{pid,"Unknown Pid"}]' -> "?.?.?" if pid is in the metadata, "Unknown Pid" if not. %% -%% `[{pid, ["My pid is ", pid], "Unknown Pid"}]' -> if pid is in the metada print "My pid is ?.?.?", otherwise print "Unknown Pid" +%% `[{pid, ["My pid is ", pid], ["Unknown Pid"]}]' -> if pid is in the metada print "My pid is ?.?.?", otherwise print "Unknown Pid" %% @end -spec format(lager_msg:lager_msg(),list(),list()) -> any(). format(Msg,[], Colors) -> @@ -86,6 +86,18 @@ T; output(severity,Msg) -> atom_to_list(lager_msg:severity(Msg)); +output(blank,_Msg) -> + output({blank," "},_Msg); +output({blank,Fill},_Msg) -> + Fill; +output(sev,Msg) -> + %% Write brief acronym for the severity level (e.g. debug -> $D) + [lager_util:level_to_chr(lager_msg:severity(Msg))]; +output(metadata, Msg) -> + output({metadata, "=", " "}, Msg); +output({metadata, IntSep, FieldSep}, Msg) -> + MD = lists:keysort(1, lager_msg:metadata(Msg)), + string:join([io_lib:format("~s~s~p", [K, IntSep, V]) || {K, V} <- MD], FieldSep); output(Prop,Msg) when is_atom(Prop) -> Metadata = lager_msg:metadata(Msg), make_printable(get_metadata(Prop,Metadata,<<"Undefined">>)); @@ -101,8 +113,47 @@ _ -> [ output(V, Msg) || V <- Present] end; +output({Prop, Present, Absent, Width}, Msg) when is_atom(Prop) -> + %% sort of like a poor man's ternary operator + Metadata = lager_msg:metadata(Msg), + case get_metadata(Prop, Metadata) of + undefined -> + [ output(V, Msg, Width) || V <- Absent]; + _ -> + [ output(V, Msg, Width) || V <- Present] + end; output(Other,_) -> make_printable(Other). +output(message, Msg, _Width) -> lager_msg:message(Msg); +output(date,Msg, _Width) -> + {D, _T} = lager_msg:datetime(Msg), + D; +output(time, Msg, _Width) -> + {_D, T} = lager_msg:datetime(Msg), + T; +output(severity, Msg, Width) -> + make_printable(atom_to_list(lager_msg:severity(Msg)), Width); +output(sev,Msg, _Width) -> + %% Write brief acronym for the severity level (e.g. debug -> $D) + [lager_util:level_to_chr(lager_msg:severity(Msg))]; +output(blank,_Msg, _Width) -> + output({blank, " "},_Msg, _Width); +output({blank, Fill},_Msg, _Width) -> + Fill; +output(metadata, Msg, _Width) -> + output({metadata, "=", " "}, Msg, _Width); +output({metadata, IntSep, FieldSep}, Msg, _Width) -> + MD = lists:keysort(1, lager_msg:metadata(Msg)), + [string:join([io_lib:format("~s~s~p", [K, IntSep, V]) || {K, V} <- MD], FieldSep)]; + +output(Prop, Msg, Width) when is_atom(Prop) -> + Metadata = lager_msg:metadata(Msg), + make_printable(get_metadata(Prop,Metadata,<<"Undefined">>), Width); +output({Prop,Default},Msg, Width) when is_atom(Prop) -> + Metadata = lager_msg:metadata(Msg), + make_printable(get_metadata(Prop,Metadata,output(Default,Msg)), Width); +output(Other,_, Width) -> make_printable(Other, Width). + output_color(_Msg,[]) -> []; output_color(Msg,Colors) -> Level = lager_msg:severity(Msg), @@ -117,6 +168,21 @@ make_printable(L) when is_list(L) orelse is_binary(L) -> L; make_printable(Other) -> io_lib:format("~p",[Other]). +make_printable(A,W) when is_integer(W)-> string:left(make_printable(A),W); +make_printable(A,{Align,W}) when is_integer(W) -> + case Align of + left -> + string:left(make_printable(A),W); + centre -> + string:centre(make_printable(A),W); + right -> + string:right(make_printable(A),W); + _ -> + string:left(make_printable(A),W) + end; + +make_printable(A,_W) -> make_printable(A). + get_metadata(Key, Metadata) -> get_metadata(Key, Metadata, undefined). @@ -164,7 +230,7 @@ [date, " ", time," [",severity,"] ",pid, " ", message, "\n"] ))) }, - {"Non existant metadata can default to string", + {"Non existent metadata can default to string", ?_assertEqual(iolist_to_binary([Date, " ", Time, " [error] Fallback Message\n"]), iolist_to_binary(format(lager_msg:new("Message", Now, @@ -174,7 +240,7 @@ [date, " ", time," [",severity,"] ",{does_not_exist,"Fallback"}, " ", message, "\n"] ))) }, - {"Non existant metadata can default to other metadata", + {"Non existent metadata can default to other metadata", ?_assertEqual(iolist_to_binary([Date, " ", Time, " [error] Fallback Message\n"]), iolist_to_binary(format(lager_msg:new("Message", Now, @@ -183,7 +249,145 @@ []), [date, " ", time," [",severity,"] ",{does_not_exist,pid}, " ", message, "\n"] ))) + }, + {"Non existent metadata can default to a string2", + ?_assertEqual(iolist_to_binary(["Unknown Pid"]), + iolist_to_binary(format(lager_msg:new("Message", + Now, + error, + [], + []), + [{pid, ["My pid is ", pid], ["Unknown Pid"]}] + ))) + }, + {"Metadata can have extra formatting", + ?_assertEqual(iolist_to_binary(["My pid is hello"]), + iolist_to_binary(format(lager_msg:new("Message", + Now, + error, + [{pid, hello}], + []), + [{pid, ["My pid is ", pid], ["Unknown Pid"]}] + ))) + }, + {"Metadata can have extra formatting1", + ?_assertEqual(iolist_to_binary(["servername"]), + iolist_to_binary(format(lager_msg:new("Message", + Now, + error, + [{pid, hello}, {server, servername}], + []), + [{server,{pid, ["(", pid, ")"], ["(Unknown Server)"]}}] + ))) + }, + {"Metadata can have extra formatting2", + ?_assertEqual(iolist_to_binary(["(hello)"]), + iolist_to_binary(format(lager_msg:new("Message", + Now, + error, + [{pid, hello}], + []), + [{server,{pid, ["(", pid, ")"], ["(Unknown Server)"]}}] + ))) + }, + {"Metadata can have extra formatting3", + ?_assertEqual(iolist_to_binary(["(Unknown Server)"]), + iolist_to_binary(format(lager_msg:new("Message", + Now, + error, + [], + []), + [{server,{pid, ["(", pid, ")"], ["(Unknown Server)"]}}] + ))) + }, + {"Metadata can be printed in its enterity", + ?_assertEqual(iolist_to_binary(["bar=2 baz=3 foo=1"]), + iolist_to_binary(format(lager_msg:new("Message", + Now, + error, + [{foo, 1}, {bar, 2}, {baz, 3}], + []), + [metadata] + ))) + }, + {"Metadata can be printed in its enterity with custom seperators", + ?_assertEqual(iolist_to_binary(["bar->2, baz->3, foo->1"]), + iolist_to_binary(format(lager_msg:new("Message", + Now, + error, + [{foo, 1}, {bar, 2}, {baz, 3}], + []), + [{metadata, "->", ", "}] + ))) + },
View file
lager-2.1.0.tar.gz/src/lager_file_backend.erl -> lager-3.1.0.tar.gz/src/lager_file_backend.erl
Changed
@@ -63,6 +63,7 @@ size = 0 :: integer(), date :: undefined | string(), count = 10 :: integer(), + shaper :: lager_shaper(), formatter :: atom(), formatter_config :: any(), sync_on :: {'mask', integer()}, @@ -74,26 +75,27 @@ -type option() :: {file, string()} | {level, lager:log_level()} | {size, non_neg_integer()} | {date, string()} | - {count, non_neg_integer()} | {sync_interval, non_neg_integer()} | + {count, non_neg_integer()} | {high_water_mark, non_neg_integer()} | + {sync_interval, non_neg_integer()} | {sync_size, non_neg_integer()} | {sync_on, lager:log_level()} | {check_interval, non_neg_integer()} | {formatter, atom()} | {formatter_config, term()}. -spec init([option(),...]) -> {ok, #state{}} | {error, bad_config}. init({FileName, LogLevel}) when is_list(FileName), is_atom(LogLevel) -> - %% backwards compatability hack + %% backwards compatibility hack init([{file, FileName}, {level, LogLevel}]); init({FileName, LogLevel, Size, Date, Count}) when is_list(FileName), is_atom(LogLevel) -> - %% backwards compatability hack + %% backwards compatibility hack init([{file, FileName}, {level, LogLevel}, {size, Size}, {date, Date}, {count, Count}]); init([{FileName, LogLevel, Size, Date, Count}, {Formatter,FormatterConfig}]) when is_list(FileName), is_atom(LogLevel), is_atom(Formatter) -> - %% backwards compatability hack + %% backwards compatibility hack init([{file, FileName}, {level, LogLevel}, {size, Size}, {date, Date}, {count, Count}, {formatter, Formatter}, {formatter_config, FormatterConfig}]); init([LogFile,{Formatter}]) -> - %% backwards compatability hack + %% backwards compatibility hack init([LogFile,{Formatter,[]}]); init([{FileName, LogLevel}, {Formatter,FormatterConfig}]) when is_list(FileName), is_atom(LogLevel), is_atom(Formatter) -> - %% backwards compatability hack + %% backwards compatibility hack init([{file, FileName}, {level, LogLevel}, {formatter, Formatter}, {formatter_config, FormatterConfig}]); init(LogFileConfig) when is_list(LogFileConfig) -> case validate_logfile_proplist(LogFileConfig) of @@ -102,10 +104,12 @@ {error, {fatal, bad_config}}; Config -> %% probabably a better way to do this, but whatever - [Name, Level, Date, Size, Count, SyncInterval, SyncSize, SyncOn, CheckInterval, Formatter, FormatterConfig] = - [proplists:get_value(Key, Config) || Key <- [file, level, date, size, count, sync_interval, sync_size, sync_on, check_interval, formatter, formatter_config]], + [RelName, Level, Date, Size, Count, HighWaterMark, SyncInterval, SyncSize, SyncOn, CheckInterval, Formatter, FormatterConfig] = + [proplists:get_value(Key, Config) || Key <- [file, level, date, size, count, high_water_mark, sync_interval, sync_size, sync_on, check_interval, formatter, formatter_config]], + Name = lager_util:expand_path(RelName), schedule_rotation(Name, Date), - State0 = #state{name=Name, level=Level, size=Size, date=Date, count=Count, formatter=Formatter, + Shaper = #lager_shaper{hwm=HighWaterMark}, + State0 = #state{name=Name, level=Level, size=Size, date=Date, count=Count, shaper=Shaper, formatter=Formatter, formatter_config=FormatterConfig, sync_on=SyncOn, sync_interval=SyncInterval, sync_size=SyncSize, check_interval=CheckInterval}, State = case lager_util:open_logfile(Name, {SyncSize, SyncInterval}) of @@ -129,15 +133,45 @@ end; handle_call(get_loglevel, #state{level=Level} = State) -> {ok, Level, State}; +handle_call({set_loghwm, Hwm}, #state{shaper=Shaper, name=Name} = State) -> + case validate_logfile_proplist([{file, Name}, {high_water_mark, Hwm}]) of + false -> + {ok, {error, bad_log_hwm}, State}; + _ -> + NewShaper = Shaper#lager_shaper{hwm=Hwm}, + ?INT_LOG(notice, "Changed loghwm of ~s to ~p", [Name, Hwm]), + {ok, {last_loghwm, Shaper#lager_shaper.hwm}, State#state{shaper=NewShaper}} + end; +handle_call(rotate, State = #state{name=File}) -> + {ok, NewState} = handle_info({rotate, File}, State), + {ok, ok, NewState}; handle_call(_Request, State) -> {ok, ok, State}. %% @private handle_event({log, Message}, - #state{name=Name, level=L,formatter=Formatter,formatter_config=FormatConfig} = State) -> + #state{name=Name, level=L, shaper=Shaper, formatter=Formatter,formatter_config=FormatConfig} = State) -> case lager_util:is_loggable(Message,L,{lager_file_backend, Name}) of true -> - {ok,write(State, lager_msg:timestamp(Message), lager_msg:severity_as_int(Message), Formatter:format(Message,FormatConfig)) }; + case lager_util:check_hwm(Shaper) of + {true, Drop, #lager_shaper{hwm=Hwm} = NewShaper} -> + NewState = case Drop > 0 of + true -> + Report = io_lib:format( + "lager_file_backend dropped ~p messages in the last second that exceeded the limit of ~p messages/sec", + [Drop, Hwm]), + ReportMsg = lager_msg:new(Report, warning, [], []), + write(State, lager_msg:timestamp(ReportMsg), + lager_msg:severity_as_int(ReportMsg), Formatter:format(ReportMsg, FormatConfig)); + false -> + State + end, + {ok,write(NewState#state{shaper=NewShaper}, + lager_msg:timestamp(Message), lager_msg:severity_as_int(Message), + Formatter:format(Message,FormatConfig))}; + {false, _, NewShaper} -> + {ok, State#state{shaper=NewShaper}} + end; false -> {ok, State} end; @@ -147,23 +181,23 @@ %% @private handle_info({rotate, File}, #state{name=File,count=Count,date=Date} = State) -> _ = lager_util:rotate_logfile(File, Count), + State1 = close_file(State), schedule_rotation(File, Date), - {ok, State}; + {ok, State1}; handle_info(_Info, State) -> {ok, State}. %% @private -terminate(_Reason, #state{fd=FD}) -> - %% flush and close any file handles - _ = file:datasync(FD), - _ = file:close(FD), +terminate(_Reason, State) -> + %% leaving this function call unmatched makes dialyzer cranky + _ = close_file(State), ok. %% @private code_change(_OldVsn, State, _Extra) -> {ok, State}. -%% @private convert the config into a gen_event handler ID +%% Convert the config into a gen_event handler ID config_to_id({Name,_Severity}) when is_list(Name) -> {?MODULE, Name}; config_to_id({Name,_Severity,_Size,_Rotation,_Count}) -> @@ -236,7 +270,7 @@ Flap end, State#state{flap=Flap2}; - _ -> + _ -> State end. @@ -300,6 +334,13 @@ _ -> throw({bad_config, "Invalid rotation count", Count}) end; +validate_logfile_proplist([{high_water_mark, HighWaterMark}|Tail], Acc) -> + case HighWaterMark of + Hwm when is_integer(Hwm), Hwm >= 0 -> + validate_logfile_proplist(Tail, [{high_water_mark, Hwm}|Acc]); + _ -> + throw({bad_config, "Invalid high water mark", HighWaterMark}) + end; validate_logfile_proplist([{date, Date}|Tail], Acc) -> case lager_util:parse_rotation_date_spec(Date) of {ok, Spec} -> @@ -363,6 +404,14 @@ erlang:send_after(lager_util:calculate_next_rotation(Date) * 1000, self(), {rotate, Name}), ok. +close_file(#state{fd=undefined} = State) -> + State; +close_file(#state{fd=FD} = State) -> + %% Flush and close any file handles. + _ = file:datasync(FD), + _ = file:close(FD), + State#state{fd=undefined}. + -ifdef(TEST). get_loglevel_test() -> @@ -591,6 +640,16 @@ ?assert(filelib:is_regular("test.log.0")) end }, + {"rotation call should work", + fun() -> + gen_event:add_handler(lager_event, {lager_file_backend, "test.log"}, [{file, "test.log"}, {level, info}, {check_interval, 1000}]), + lager:log(error, self(), "Test message1"), + lager:log(error, self(), "Test message1"), + gen_event:call(lager_event, {lager_file_backend, "test.log"}, rotate, infinity), + lager:log(error, self(), "Test message1"), + ?assert(filelib:is_regular("test.log.0")) + end + }, {"sync_on option should work", fun() -> gen_event:add_handler(lager_event, lager_file_backend, [{file, "test.log"}, {level, info}, {sync_on, "=info"}, {check_interval, 5000}, {sync_interval, 5000}]), @@ -665,8 +724,8 @@ {"test.log", critical}), lager:error("Test message"), ?assertEqual({ok, <<>>}, file:read_file("test.log")), - {Level, _} = lager_config:get(loglevel), - lager_config:set(loglevel, {Level, [{[{module, + {Level, _} = lager_config:get({lager_event, loglevel}), + lager_config:set({lager_event, loglevel}, {Level, [{[{module, ?MODULE}], ?DEBUG,
View file
lager-2.1.0.tar.gz/src/lager_handler_watcher.erl -> lager-3.1.0.tar.gz/src/lager_handler_watcher.erl
Changed
@@ -38,18 +38,18 @@ -record(state, { module :: atom(), config :: any(), - event :: pid() | atom() + sink :: pid() | atom() }). -start_link(Event, Module, Config) -> - gen_server:start_link(?MODULE, [Event, Module, Config], []). +start_link(Sink, Module, Config) -> + gen_server:start_link(?MODULE, [Sink, Module, Config], []). -start(Event, Module, Config) -> - gen_server:start(?MODULE, [Event, Module, Config], []). +start(Sink, Module, Config) -> + gen_server:start(?MODULE, [Sink, Module, Config], []). -init([Event, Module, Config]) -> - install_handler(Event, Module, Config), - {ok, #state{event=Event, module=Module, config=Config}}. +init([Sink, Module, Config]) -> + install_handler(Sink, Module, Config), + {ok, #state{sink=Sink, module=Module, config=Config}}. handle_call(_Call, _From, State) -> {reply, ok, State}. @@ -62,18 +62,18 @@ handle_info({gen_event_EXIT, Module, shutdown}, #state{module=Module} = State) -> {stop, normal, State}; handle_info({gen_event_EXIT, Module, Reason}, #state{module=Module, - config=Config, event=Event} = State) -> + config=Config, sink=Sink} = State) -> case lager:log(error, self(), "Lager event handler ~p exited with reason ~s", [Module, error_logger_lager_h:format_reason(Reason)]) of ok -> - install_handler(Event, Module, Config); + install_handler(Sink, Module, Config); {error, _} -> %% lager is not working, so installing a handler won't work ok end, {noreply, State}; -handle_info(reinstall_handler, #state{module=Module, config=Config, event=Event} = State) -> - install_handler(Event, Module, Config), +handle_info(reinstall_handler, #state{module=Module, config=Config, sink=Sink} = State) -> + install_handler(Sink, Module, Config), {noreply, State}; handle_info(stop, State) -> {stop, normal, State}; @@ -87,23 +87,33 @@ {ok, State}. %% internal - -install_handler(Event, Module, Config) -> - case gen_event:add_sup_handler(Event, Module, Config) of +install_handler(Sink, lager_backend_throttle, Config) -> + %% The lager_backend_throttle needs to know to which sink it is + %% attached, hence this admittedly ugly workaround. Handlers are + %% sensitive to the structure of the configuration sent to `init', + %% sadly, so it's not trivial to add a configuration item to be + %% ignored to backends without breaking 3rd party handlers. + install_handler2(Sink, lager_backend_throttle, [{sink, Sink}|Config]); +install_handler(Sink, Module, Config) -> + install_handler2(Sink, Module, Config). + +%% private +install_handler2(Sink, Module, Config) -> + case gen_event:add_sup_handler(Sink, Module, Config) of ok -> - ?INT_LOG(debug, "Lager installed handler ~p into ~p", [Module, Event]), - lager:update_loglevel_config(), + ?INT_LOG(debug, "Lager installed handler ~p into ~p", [Module, Sink]), + lager:update_loglevel_config(Sink), ok; {error, {fatal, Reason}} -> ?INT_LOG(error, "Lager fatally failed to install handler ~p into" - " ~p, NOT retrying: ~p", [Module, Event, Reason]), + " ~p, NOT retrying: ~p", [Module, Sink, Reason]), %% tell ourselves to stop self() ! stop, ok; Error -> %% try to reinstall it later ?INT_LOG(error, "Lager failed to install handler ~p into" - " ~p, retrying later : ~p", [Module, Event, Error]), + " ~p, retrying later : ~p", [Module, Sink, Error]), erlang:send_after(5000, self(), reinstall_handler), ok end.
View file
lager-2.1.0.tar.gz/src/lager_stdlib.erl -> lager-3.1.0.tar.gz/src/lager_stdlib.erl
Changed
@@ -39,7 +39,7 @@ string_p(Term) -> string_p1(Term). -string_p1([H|T]) when is_integer(H), H >= $\s, H < 255 -> +string_p1([H|T]) when is_integer(H), H >= $\s, H < 256 -> string_p1(T); string_p1([$\n|T]) -> string_p1(T); string_p1([$\r|T]) -> string_p1(T);
View file
lager-2.1.0.tar.gz/src/lager_sup.erl -> lager-3.1.0.tar.gz/src/lager_sup.erl
Changed
@@ -34,9 +34,14 @@ init([]) -> %% set up the config, is safe even during relups lager_config:new(), + %% TODO: + %% Always start lager_event as the default and make sure that + %% other gen_event stuff can start up as needed + %% + %% Maybe a new API to handle the sink and its policy? Children = [ {lager, {gen_event, start_link, [{local, lager_event}]}, - permanent, 5000, worker, [dynamic]}, + permanent, 5000, worker, dynamic}, {lager_handler_watcher_sup, {lager_handler_watcher_sup, start_link, []}, permanent, 5000, supervisor, [lager_handler_watcher_sup]}],
View file
lager-2.1.0.tar.gz/src/lager_transform.erl -> lager-3.1.0.tar.gz/src/lager_transform.erl
Changed
@@ -31,8 +31,10 @@ parse_transform(AST, Options) -> TruncSize = proplists:get_value(lager_truncation_size, Options, ?DEFAULT_TRUNCATION), Enable = proplists:get_value(lager_print_records_flag, Options, true), + Sinks = [lager] ++ proplists:get_value(lager_extra_sinks, Options, []), put(print_records_flag, Enable), put(truncation_size, TruncSize), + put(sinks, Sinks), erlang:put(records, []), %% .app file should either be in the outdir, or the same dir as the source file guess_application(proplists:get_value(outdir, Options), hd(AST)), @@ -75,138 +77,163 @@ walk_body(Acc, []) -> lists:reverse(Acc); walk_body(Acc, [H|T]) -> - walk_body([transform_statement(H)|Acc], T). + walk_body([transform_statement(H, get(sinks))|Acc], T). -transform_statement({call, Line, {remote, _Line1, {atom, _Line2, lager}, - {atom, _Line3, Severity}}, Arguments0} = Stmt) -> - case lists:member(Severity, ?LEVELS) of +transform_statement({call, Line, {remote, _Line1, {atom, _Line2, Module}, + {atom, _Line3, Function}}, Arguments0} = Stmt, + Sinks) -> + case lists:member(Module, Sinks) of true -> - SeverityAsInt=lager_util:level_to_num(Severity), - DefaultAttrs0 = {cons, Line, {tuple, Line, [ - {atom, Line, module}, {atom, Line, get(module)}]}, - {cons, Line, {tuple, Line, [ - {atom, Line, function}, {atom, Line, get(function)}]}, - {cons, Line, {tuple, Line, [ - {atom, Line, line}, - {integer, Line, Line}]}, - {cons, Line, {tuple, Line, [ - {atom, Line, pid}, - {call, Line, {atom, Line, pid_to_list}, [ - {call, Line, {atom, Line ,self}, []}]}]}, - {cons, Line, {tuple, Line, [ - {atom, Line, node}, - {call, Line, {atom, Line, node}, []}]}, - %% get the metadata with lager:md(), this will always return a list so we can use it as the tail here - {call, Line, {remote, Line, {atom, Line, lager}, {atom, Line, md}}, []}}}}}}, - %{nil, Line}}}}}}}, - DefaultAttrs = case erlang:get(application) of - undefined -> - DefaultAttrs0; - App -> - %% stick the application in the attribute list - concat_lists({cons, Line, {tuple, Line, [ - {atom, Line, application}, - {atom, Line, App}]}, - {nil, Line}}, DefaultAttrs0) - end, - {Traces, Message, Arguments} = case Arguments0 of - [Format] -> - {DefaultAttrs, Format, {atom, Line, none}}; - [Arg1, Arg2] -> - %% some ambiguity here, figure out if these arguments are - %% [Format, Args] or [Attr, Format]. - %% The trace attributes will be a list of tuples, so check - %% for that. - case {element(1, Arg1), Arg1} of - {_, {cons, _, {tuple, _, _}, _}} -> - {concat_lists(Arg1, DefaultAttrs), - Arg2, {atom, Line, none}}; - {Type, _} when Type == var; - Type == lc; - Type == call; - Type == record_field -> - %% crap, its not a literal. look at the second - %% argument to see if it is a string - case Arg2 of - {string, _, _} -> - {concat_lists(Arg1, DefaultAttrs), - Arg2, {atom, Line, none}}; - _ -> - %% not a string, going to have to guess - %% it's the argument list - {DefaultAttrs, Arg1, Arg2} - end; - _ -> - {DefaultAttrs, Arg1, Arg2} - end; - [Attrs, Format, Args] -> - {concat_lists(Attrs, DefaultAttrs), Format, Args} - end, - %% Generate some unique variable names so we don't accidentaly export from case clauses. - %% Note that these are not actual atoms, but the AST treats variable names as atoms. - LevelVar = make_varname("__Level", Line), - TracesVar = make_varname("__Traces", Line), - PidVar = make_varname("__Pid", Line), - %% Wrap the call to lager_dispatch log in a case that will avoid doing any work if this message is not elegible for logging - %% case {whereis(lager_event(lager_event), lager_config:get(loglevel, {?LOG_NONE, []})} of - {'case', Line, - {tuple, Line, - [{call, Line, {atom, Line, whereis}, [{atom, Line, lager_event}]}, - {call, Line, {remote, Line, {atom, Line, lager_config}, {atom, Line, get}}, [{atom, Line, loglevel}, {tuple, Line, [{integer, Line, 0},{nil, Line}]}]}]}, - [ - %% {undefined, _} -> {error, lager_not_running} - {clause, Line, - [{tuple, Line, [{atom, Line, undefined}, {var, Line, '_'}]}], - [], - %% trick the linter into avoiding a 'term constructed by not used' error: - %% (fun() -> {error, lager_not_running} end)(); - [{call, Line, {'fun', Line, {clauses, [{clause, Line, [],[], [{tuple, Line, [{atom, Line, error},{atom, Line, lager_not_running}]}]}]}}, []}]}, - %% If we care about the loglevel, or there's any traces installed, we have do more checking - %% {Level, Traces} when (Level band SeverityAsInt) /= 0 orelse Traces /= [] -> - {clause, Line, - [{tuple, Line, [{var, Line, PidVar}, {tuple, Line, [{var, Line, LevelVar}, {var, Line, TracesVar}]}]}], - [[{op, Line, 'orelse', - {op, Line, '/=', {op, Line, 'band', {var, Line, LevelVar}, {integer, Line, SeverityAsInt}}, {integer, Line, 0}}, - {op, Line, '/=', {var, Line, TracesVar}, {nil, Line}}}]], - [ - %% do the call to lager:dispatch_log - {call, Line, {remote, Line, {atom, Line, lager}, {atom, Line, do_log}}, - [ - {atom,Line,Severity}, - Traces, - Message, - Arguments, - {integer, Line, get(truncation_size)}, - {integer, Line, SeverityAsInt}, - {var, Line, LevelVar}, - {var, Line, TracesVar}, - {var, Line, PidVar} - ] - } - ]}, - %% otherwise, do nothing - %% _ -> ok - {clause, Line, [{var, Line, '_'}],[],[{atom, Line, ok}]} - ]}; + case lists:member(Function, ?LEVELS) of + true -> + SinkName = lager_util:make_internal_sink_name(Module), + do_transform(Line, SinkName, Function, Arguments0); + false -> + case lists:keyfind(Function, 1, ?LEVELS_UNSAFE) of + {Function, Severity} -> + SinkName = lager_util:make_internal_sink_name(Module), + do_transform(Line, SinkName, Severity, Arguments0, unsafe); + false -> + Stmt + end + end; false -> - Stmt + list_to_tuple(transform_statement(tuple_to_list(Stmt), Sinks)) end; -transform_statement({call, Line, {remote, Line1, {atom, Line2, boston_lager}, - {atom, Line3, Severity}}, Arguments}) -> - NewArgs = case Arguments of - [{string, L, Msg}] -> [{string, L, re:replace(Msg, "r", "h", [{return, list}, global])}]; - [{string, L, Format}, Args] -> [{string, L, re:replace(Format, "r", "h", [{return, list}, global])}, Args]; - Other -> Other - end, - transform_statement({call, Line, {remote, Line1, {atom, Line2, lager}, - {atom, Line3, Severity}}, NewArgs}); -transform_statement(Stmt) when is_tuple(Stmt) -> - list_to_tuple(transform_statement(tuple_to_list(Stmt))); -transform_statement(Stmt) when is_list(Stmt) -> - [transform_statement(S) || S <- Stmt]; -transform_statement(Stmt) -> +transform_statement(Stmt, Sinks) when is_tuple(Stmt) -> + list_to_tuple(transform_statement(tuple_to_list(Stmt), Sinks)); +transform_statement(Stmt, Sinks) when is_list(Stmt) -> + [transform_statement(S, Sinks) || S <- Stmt]; +transform_statement(Stmt, _Sinks) -> Stmt. +do_transform(Line, SinkName, Severity, Arguments0) -> + do_transform(Line, SinkName, Severity, Arguments0, safe). + +do_transform(Line, SinkName, Severity, Arguments0, Safety) -> + SeverityAsInt=lager_util:level_to_num(Severity), + DefaultAttrs0 = {cons, Line, {tuple, Line, [ + {atom, Line, module}, {atom, Line, get(module)}]}, + {cons, Line, {tuple, Line, [ + {atom, Line, function}, {atom, Line, get(function)}]}, + {cons, Line, {tuple, Line, [ + {atom, Line, line}, + {integer, Line, Line}]}, + {cons, Line, {tuple, Line, [ + {atom, Line, pid}, + {call, Line, {atom, Line, pid_to_list}, [ + {call, Line, {atom, Line ,self}, []}]}]}, + {cons, Line, {tuple, Line, [ + {atom, Line, node}, + {call, Line, {atom, Line, node}, []}]}, + %% get the metadata with lager:md(), this will always return a list so we can use it as the tail here + {call, Line, {remote, Line, {atom, Line, lager}, {atom, Line, md}}, []}}}}}}, + %{nil, Line}}}}}}}, + DefaultAttrs = case erlang:get(application) of + undefined -> + DefaultAttrs0; + App -> + %% stick the application in the attribute list + concat_lists({cons, Line, {tuple, Line, [ + {atom, Line, application},
View file
lager-2.1.0.tar.gz/src/lager_trunc_io.erl -> lager-3.1.0.tar.gz/src/lager_trunc_io.erl
Changed
@@ -3,12 +3,12 @@ %% compliance with the License. You should have received a copy of the %% Erlang Public License along with your Erlang distribution. If not, it can be %% retrieved via the world wide web at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% The Initial Developer of the Original Code is Corelatus AB. %% Portions created by Corelatus are Copyright 2003, Corelatus %% AB. All Rights Reserved.'' @@ -32,7 +32,7 @@ -module(lager_trunc_io). -author('matthias@corelatus.se'). -%% And thanks to Chris Newcombe for a bug fix +%% And thanks to Chris Newcombe for a bug fix -export([format/3, format/4, print/2, print/3, fprint/2, fprint/3, safe/2]). % interface functions -version("$Id: trunc_io.erl,v 1.11 2009-02-23 12:01:06 matthias Exp $"). @@ -76,11 +76,11 @@ %% @doc Returns an flattened list containing the ASCII representation of the given %% term. -spec fprint(term(), pos_integer(), options()) -> string(). -fprint(T, Max, Options) -> +fprint(T, Max, Options) -> {L, _} = print(T, Max, prepare_options(Options, #print_options{})), lists:flatten(L). -%% @doc Same as print, but never crashes. +%% @doc Same as print, but never crashes. %% %% This is a tradeoff. Print might conceivably crash if it's asked to %% print something it doesn't understand, for example some new data @@ -88,7 +88,7 @@ %% to io_lib to format the term, but then the formatting is %% depth-limited instead of length limited, so you might run out %% memory printing it. Out of the frying pan and into the fire. -%% +%% -spec safe(term(), pos_integer()) -> {string(), pos_integer()} | {string()}. safe(What, Len) -> case catch print(What, Len) of @@ -114,8 +114,8 @@ print(_, _, #print_options{depth=0}) -> {"...", 3}; -%% @doc We assume atoms, floats, funs, integers, PIDs, ports and refs never need -%% to be truncated. This isn't strictly true, someone could make an +%% @doc We assume atoms, floats, funs, integers, PIDs, ports and refs never need +%% to be truncated. This isn't strictly true, someone could make an %% arbitrarily long bignum. Let's assume that won't happen unless someone %% is being malicious. %% @@ -214,15 +214,15 @@ SizeStr = integer_to_list(Size), {[ValueStr, $:, SizeStr], length(ValueStr) + length(SizeStr) +1}; print(BitString, Max, Options) when is_bitstring(BitString) -> - case byte_size(BitString) > Max of + BL = case byte_size(BitString) > Max of true -> - BL = binary_to_list(BitString, 1, Max); + binary_to_list(BitString, 1, Max); _ -> R = erlang:bitstring_to_list(BitString), {Bytes, [Bits]} = lists:splitwith(fun erlang:is_integer/1, R), %% tag the trailing bits with a special tuple we catch when %% list_body calls print again - BL = Bytes ++ [{inline_bitstring, Bits}] + Bytes ++ [{inline_bitstring, Bits}] end, {X, Len0} = list_body(BL, Max - 4, dec_depth(Options), true), {["<<", X, ">>"], Len0 + 4}; @@ -265,7 +265,7 @@ {RC, Len} = record_fields(Fields, Max - length(Leader) + 1, dec_depth(Options)), {[Leader, RC, "}"], Len + length(Leader) + 1}; -print(Tuple, Max, Options) when is_tuple(Tuple) -> +print(Tuple, Max, Options) when is_tuple(Tuple) -> {TC, Len} = tuple_contents(Tuple, Max-2, Options), {[${, TC, $}], Len + 2}; @@ -307,7 +307,7 @@ false -> $| end, {[List ++ [Sep | "..."]], Len + 4}; -list_body([H|T], Max, Options, Tuple) -> +list_body([H|T], Max, Options, Tuple) -> {List, Len} = print(H, Max, Options), {Final, FLen} = list_bodyc(T, Max - Len, Options, Tuple), {[List|Final], FLen + Len}; @@ -319,7 +319,7 @@ list_bodyc(_, Max, _Options, _Tuple) when Max < 5 -> {",...", 4}; list_bodyc(_, _Max, #print_options{depth=1}, true) -> {",...", 4}; list_bodyc(_, _Max, #print_options{depth=1}, false) -> {"|...", 4}; -list_bodyc([H|T], Max, #print_options{depth=Depth} = Options, Tuple) -> +list_bodyc([H|T], Max, #print_options{depth=Depth} = Options, Tuple) -> {List, Len} = print(H, Max, dec_depth(Options)), {Final, FLen} = list_bodyc(T, Max - Len - 1, dec_depth(Options), Tuple), Sep = case Depth == 1 andalso not Tuple of @@ -553,7 +553,7 @@ test(M,F), perf(M,F,Reps-1); perf(_,_,_) -> - done. + done. %% Performance test. Needs a particularly large term I saved as a binary... -spec perf1() -> {non_neg_integer(), non_neg_integer()}. @@ -570,7 +570,7 @@ ?assertEqual("[\"foo\",98,97,114]", lists:flatten(format("~p", [["foo", $b, $a, $r]], 50))), ?assertEqual("[\"foo\",98,97,114]", lists:flatten(format("~P", [["foo", $b, $a, $r], 10], 50))), ?assertEqual("[[102,111,111],98,97,114]", lists:flatten(format("~w", [["foo", $b, $a, $r]], 50))), - + %% complex ones ?assertEqual(" foobar", lists:flatten(format("~10s", [["foo", $b, $a, $r]], 50))), ?assertEqual("f", lists:flatten(format("~1s", [["foo", $b, $a, $r]], 50))), @@ -836,7 +836,7 @@ ?assertEqual("[1|...]", lists:flatten(format("~P", [[1, 2, 3], 2], 50))), ?assertEqual("[1,2|...]", lists:flatten(format("~P", [[1, 2, 3], 3], 50))), ?assertEqual("[1,2,3]", lists:flatten(format("~P", [[1, 2, 3], 4], 50))), - + ?assertEqual("{1,...}", lists:flatten(format("~P", [{1, 2, 3}, 2], 50))), ?assertEqual("{1,2,...}", lists:flatten(format("~P", [{1, 2, 3}, 3], 50))), ?assertEqual("{1,2,3}", lists:flatten(format("~P", [{1, 2, 3}, 4], 50))), @@ -845,13 +845,13 @@ ?assertEqual("[1,2|...]", lists:flatten(format("~P", [[1, 2, <<3>>], 3], 50))), ?assertEqual("[1,2,<<...>>]", lists:flatten(format("~P", [[1, 2, <<3>>], 4], 50))), ?assertEqual("[1,2,<<3>>]", lists:flatten(format("~P", [[1, 2, <<3>>], 5], 50))), - + ?assertEqual("<<...>>", lists:flatten(format("~P", [<<0, 0, 0, 0>>, 1], 50))), ?assertEqual("<<0,...>>", lists:flatten(format("~P", [<<0, 0, 0, 0>>, 2], 50))), ?assertEqual("<<0,0,...>>", lists:flatten(format("~P", [<<0, 0, 0, 0>>, 3], 50))), ?assertEqual("<<0,0,0,...>>", lists:flatten(format("~P", [<<0, 0, 0, 0>>, 4], 50))), ?assertEqual("<<0,0,0,0>>", lists:flatten(format("~P", [<<0, 0, 0, 0>>, 5], 50))), - + %% this is a seriously weird edge case ?assertEqual("<<\" \"...>>", lists:flatten(format("~P", [<<32, 32, 32, 0>>, 2], 50))), ?assertEqual("<<\" \"...>>", lists:flatten(format("~P", [<<32, 32, 32, 0>>, 3], 50))),
View file
lager-2.1.0.tar.gz/src/lager_util.erl -> lager-3.1.0.tar.gz/src/lager_util.erl
Changed
@@ -18,11 +18,12 @@ -include_lib("kernel/include/file.hrl"). --export([levels/0, level_to_num/1, num_to_level/1, config_to_mask/1, config_to_levels/1, mask_to_levels/1, +-export([levels/0, level_to_num/1, level_to_chr/1, + num_to_level/1, config_to_mask/1, config_to_levels/1, mask_to_levels/1, open_logfile/2, ensure_logfile/4, rotate_logfile/2, format_time/0, format_time/1, localtime_ms/0, localtime_ms/1, maybe_utc/1, parse_rotation_date_spec/1, calculate_next_rotation/1, validate_trace/1, check_traces/4, is_loggable/3, - trace_filter/1, trace_filter/2]). + trace_filter/1, trace_filter/2, expand_path/1, check_hwm/1, make_internal_sink_name/1]). -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). @@ -33,25 +34,35 @@ levels() -> [debug, info, notice, warning, error, critical, alert, emergency, none]. -level_to_num(debug) -> ?DEBUG; -level_to_num(info) -> ?INFO; -level_to_num(notice) -> ?NOTICE; -level_to_num(warning) -> ?WARNING; -level_to_num(error) -> ?ERROR; -level_to_num(critical) -> ?CRITICAL; -level_to_num(alert) -> ?ALERT; -level_to_num(emergency) -> ?EMERGENCY; -level_to_num(none) -> ?LOG_NONE. - -num_to_level(?DEBUG) -> debug; -num_to_level(?INFO) -> info; -num_to_level(?NOTICE) -> notice; -num_to_level(?WARNING) -> warning; -num_to_level(?ERROR) -> error; -num_to_level(?CRITICAL) -> critical; -num_to_level(?ALERT) -> alert; +level_to_num(debug) -> ?DEBUG; +level_to_num(info) -> ?INFO; +level_to_num(notice) -> ?NOTICE; +level_to_num(warning) -> ?WARNING; +level_to_num(error) -> ?ERROR; +level_to_num(critical) -> ?CRITICAL; +level_to_num(alert) -> ?ALERT; +level_to_num(emergency) -> ?EMERGENCY; +level_to_num(none) -> ?LOG_NONE. + +level_to_chr(debug) -> $D; +level_to_chr(info) -> $I; +level_to_chr(notice) -> $N; +level_to_chr(warning) -> $W; +level_to_chr(error) -> $E; +level_to_chr(critical) -> $C; +level_to_chr(alert) -> $A; +level_to_chr(emergency) -> $M; +level_to_chr(none) -> $ . + +num_to_level(?DEBUG) -> debug; +num_to_level(?INFO) -> info; +num_to_level(?NOTICE) -> notice; +num_to_level(?WARNING) -> warning; +num_to_level(?ERROR) -> error; +num_to_level(?CRITICAL) -> critical; +num_to_level(?ALERT) -> alert; num_to_level(?EMERGENCY) -> emergency; -num_to_level(?LOG_NONE) -> none. +num_to_level(?LOG_NONE) -> none. -spec config_to_mask(atom()|string()) -> {'mask', integer()}. config_to_mask(Conf) -> @@ -467,6 +478,67 @@ i3l(I) when I < 100 -> [$0 | i2l(I)]; i3l(I) -> integer_to_list(I). +%% When log_root option is provided, get the real path to a file +expand_path(RelPath) -> + case application:get_env(lager, log_root) of + {ok, LogRoot} when is_list(LogRoot) -> % Join relative path + %% check if the given RelPath contains LogRoot, if so, do not add + %% it again; see gh #304 + case string:str(filename:dirname(RelPath), LogRoot) of + X when X > 0 -> + RelPath; + _Zero -> + filename:join(LogRoot, RelPath) + end; + undefined -> % No log_root given, keep relative path + RelPath + end. + +%% Log rate limit, i.e. high water mark for incoming messages + +check_hwm(Shaper = #lager_shaper{hwm = undefined}) -> + {true, 0, Shaper}; +check_hwm(Shaper = #lager_shaper{mps = Mps, hwm = Hwm}) when Mps < Hwm -> + %% haven't hit high water mark yet, just log it + {true, 0, Shaper#lager_shaper{mps=Mps+1}}; +check_hwm(Shaper = #lager_shaper{lasttime = Last, dropped = Drop}) -> + %% are we still in the same second? + {M, S, _} = Now = os:timestamp(), + case Last of + {M, S, _} -> + %% still in same second, but have exceeded the high water mark + NewDrops = discard_messages(Now, 0), + {false, 0, Shaper#lager_shaper{dropped=Drop+NewDrops}}; + _ -> + %% different second, reset all counters and allow it + {true, Drop, Shaper#lager_shaper{dropped = 0, mps=1, lasttime = Now}} + end. + +discard_messages(Second, Count) -> + {M, S, _} = os:timestamp(), + case Second of + {M, S, _} -> + receive + %% we only discard gen_event notifications, because + %% otherwise we might discard gen_event internal + %% messages, such as trapped EXITs + {notify, _Event} -> + discard_messages(Second, Count+1) + after 0 -> + Count + end; + _ -> + Count + end. + +%% @private Build an atom for the gen_event process based on a sink name. +%% For historical reasons, the default gen_event process for lager itself is named +%% `lager_event'. For all other sinks, it is SinkName++`_lager_event' +make_internal_sink_name(lager) -> + ?DEFAULT_SINK; +make_internal_sink_name(Sink) -> + list_to_atom(atom_to_list(Sink) ++ "_lager_event"). + -ifdef(TEST). parse_test() -> @@ -707,4 +779,28 @@ ?assertEqual([debug, notice, error], mask_to_levels(?DEBUG bor ?NOTICE bor ?ERROR)), ok. +expand_path_test() -> + OldRootVal = application:get_env(lager, log_root), + + ok = application:unset_env(lager, log_root), + ?assertEqual("/foo/bar", expand_path("/foo/bar")), + ?assertEqual("foo/bar", expand_path("foo/bar")), + + ok = application:set_env(lager, log_root, "log/dir"), + ?assertEqual("/foo/bar", expand_path("/foo/bar")), % Absolute path should not be changed + ?assertEqual("log/dir/foo/bar", expand_path("foo/bar")), + ?assertEqual("log/dir/foo/bar", expand_path("log/dir/foo/bar")), %% gh #304 + + case OldRootVal of + undefined -> application:unset_env(lager, log_root); + {ok, Root} -> application:set_env(lager, log_root, Root) + end, + ok. + +sink_name_test_() -> + [ + ?_assertEqual(lager_event, make_internal_sink_name(lager)), + ?_assertEqual(audit_lager_event, make_internal_sink_name(audit)) + ]. + -endif.
View file
lager-3.1.0.tar.gz/test/compress_pr_record_test.erl
Added
@@ -0,0 +1,16 @@ +-module(compress_pr_record_test). + +-compile([{parse_transform, lager_transform}]). + +-record(a, {field1, field2, foo, bar, baz, zyu, zix}). + +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). +-endif. + +nested_record_test() -> + A = #a{field1 = "Notice me senpai"}, + Pr_A = lager:pr(A, ?MODULE), + Pr_A_Comp = lager:pr(A, ?MODULE, [compress]), + ?assertMatch({'$lager_record', a, [{field1, "Notice me senpai"}, {field2, undefined} | _]}, Pr_A), + ?assertEqual({'$lager_record', a, [{field1, "Notice me senpai"}]}, Pr_A_Comp).
View file
lager-2.1.0.tar.gz/test/crash.erl -> lager-3.1.0.tar.gz/test/crash.erl
Changed
@@ -10,8 +10,8 @@ -export([start/0]). -record(state, { - host, - port + host :: term(), + port :: term() }). start() ->
View file
lager-3.1.0.tar.gz/test/lager_rotate.erl
Added
@@ -0,0 +1,138 @@ +-module(lager_rotate). + +-compile(export_all). + +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). +-endif. + + +rotate_test_() -> + {foreach, + fun() -> + file:write_file("test1.log", ""), + file:write_file("test2.log", ""), + file:write_file("test3.log", ""), + file:delete("test1.log.0"), + file:delete("test2.log.0"), + file:delete("test3.log.0"), + error_logger:tty(false), + application:load(lager), + application:set_env(lager, handlers, + [{lager_file_backend, [{file, "test1.log"}, {level, info}]}, + {lager_file_backend, [{file, "test2.log"}, {level, info}]}]), + application:set_env(lager, extra_sinks, + [{sink_event, + [{handlers, + [{lager_file_backend, [{file, "test3.log"}, {level, info}]}]} + ]}]), + application:set_env(lager, error_logger_redirect, false), + application:set_env(lager, async_threshold, undefined), + lager:start() + end, + fun(_) -> + file:delete("test1.log"), + file:delete("test2.log"), + file:delete("test3.log"), + file:delete("test1.log.0"), + file:delete("test2.log.0"), + file:delete("test3.log.0"), + application:stop(lager), + application:stop(goldrush), + error_logger:tty(true) + end, + [{"Rotate single file", + fun() -> + lager:log(error, self(), "Test message 1"), + lager:log(sink_event, error, self(), "Sink test message 1", []), + lager:rotate_handler({lager_file_backend, "test1.log"}), + timer:sleep(1000), + true = filelib:is_regular("test1.log.0"), + lager:log(error, self(), "Test message 2"), + lager:log(sink_event, error, self(), "Sink test message 2", []), + + {ok, File1} = file:read_file("test1.log"), + {ok, File2} = file:read_file("test2.log"), + {ok, SinkFile} = file:read_file("test3.log"), + {ok, File1Old} = file:read_file("test1.log.0"), + + have_no_log(File1, <<"Test message 1">>), + have_log(File1, <<"Test message 2">>), + + have_log(File2, <<"Test message 1">>), + have_log(File2, <<"Test message 2">>), + + have_log(File1Old, <<"Test message 1">>), + have_no_log(File1Old, <<"Test message 2">>), + + have_log(SinkFile, <<"Sink test message 1">>), + have_log(SinkFile, <<"Sink test message 2">>) + end}, + {"Rotate sink", + fun() -> + lager:log(error, self(), "Test message 1"), + lager:log(sink_event, error, self(), "Sink test message 1", []), + lager:rotate_sink(sink_event), + timer:sleep(1000), + true = filelib:is_regular("test3.log.0"), + lager:log(error, self(), "Test message 2"), + lager:log(sink_event, error, self(), "Sink test message 2", []), + {ok, File1} = file:read_file("test1.log"), + {ok, File2} = file:read_file("test2.log"), + {ok, SinkFile} = file:read_file("test3.log"), + {ok, SinkFileOld} = file:read_file("test3.log.0"), + + have_log(File1, <<"Test message 1">>), + have_log(File1, <<"Test message 2">>), + + have_log(File2, <<"Test message 1">>), + have_log(File2, <<"Test message 2">>), + + have_log(SinkFileOld, <<"Sink test message 1">>), + have_no_log(SinkFileOld, <<"Sink test message 2">>), + + have_no_log(SinkFile, <<"Sink test message 1">>), + have_log(SinkFile, <<"Sink test message 2">>) + end}, + {"Rotate all", + fun() -> + lager:log(error, self(), "Test message 1"), + lager:log(sink_event, error, self(), "Sink test message 1", []), + lager:rotate_all(), + timer:sleep(1000), + true = filelib:is_regular("test3.log.0"), + lager:log(error, self(), "Test message 2"), + lager:log(sink_event, error, self(), "Sink test message 2", []), + {ok, File1} = file:read_file("test1.log"), + {ok, File2} = file:read_file("test2.log"), + {ok, SinkFile} = file:read_file("test3.log"), + {ok, File1Old} = file:read_file("test1.log.0"), + {ok, File2Old} = file:read_file("test2.log.0"), + {ok, SinkFileOld} = file:read_file("test3.log.0"), + + have_no_log(File1, <<"Test message 1">>), + have_log(File1, <<"Test message 2">>), + + have_no_log(File2, <<"Test message 1">>), + have_log(File2, <<"Test message 2">>), + + have_no_log(SinkFile, <<"Sink test message 1">>), + have_log(SinkFile, <<"Sink test message 2">>), + + have_log(SinkFileOld, <<"Sink test message 1">>), + have_no_log(SinkFileOld, <<"Sink test message 2">>), + + have_log(File1Old, <<"Test message 1">>), + have_no_log(File1Old, <<"Test message 2">>), + + have_log(File2Old, <<"Test message 1">>), + have_no_log(File2Old, <<"Test message 2">>) + + end}]}. + +have_log(Data, Log) -> + {_,_} = binary:match(Data, Log). + +have_no_log(Data, Log) -> + nomatch = binary:match(Data, Log). +
View file
lager-2.1.0.tar.gz/test/lager_test_backend.erl -> lager-3.1.0.tar.gz/test/lager_test_backend.erl
Changed
@@ -1,4 +1,6 @@ -%% Copyright (c) 2011-2012 Basho Technologies, Inc. All Rights Reserved. +%% ------------------------------------------------------------------- +%% +%% Copyright (c) 2011-2015 Basho Technologies, Inc. %% %% This file is provided to you under the Apache License, %% Version 2.0 (the "License"); you may not use this file @@ -13,6 +15,8 @@ %% KIND, either express or implied. See the License for the %% specific language governing permissions and limitations %% under the License. +%% +%% ------------------------------------------------------------------- -module(lager_test_backend). @@ -23,12 +27,15 @@ -export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2, code_change/3]). --record(state, {level, buffer, ignored}). --record(test, {attrs, format, args}). --compile([{parse_transform, lager_transform}]). +-define(TEST_SINK_NAME, '__lager_test_sink'). %% <-- used by parse transform +-define(TEST_SINK_EVENT, '__lager_test_sink_lager_event'). %% <-- used by lager API calls and internals for gen_event + +-record(state, {level :: list(), buffer :: list(), ignored :: term()}). +-compile({parse_transform, lager_transform}). -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). +-record(test, {attrs :: list(), format :: list(), args :: list()}). -export([pop/0, count/0, count_ignored/0, flush/0, print_state/0]). -endif. @@ -89,28 +96,63 @@ -ifdef(TEST). pop() -> - gen_event:call(lager_event, ?MODULE, pop). + pop(lager_event). count() -> - gen_event:call(lager_event, ?MODULE, count). + count(lager_event). count_ignored() -> - gen_event:call(lager_event, ?MODULE, count_ignored). + count_ignored(lager_event). flush() -> - gen_event:call(lager_event, ?MODULE, flush). + flush(lager_event). print_state() -> - gen_event:call(lager_event, ?MODULE, print_state). + print_state(lager_event). print_bad_state() -> - gen_event:call(lager_event, ?MODULE, print_bad_state). + print_bad_state(lager_event). + +pop(Sink) -> + gen_event:call(Sink, ?MODULE, pop). + +count(Sink) -> + gen_event:call(Sink, ?MODULE, count). + +count_ignored(Sink) -> + gen_event:call(Sink, ?MODULE, count_ignored). + +flush(Sink) -> + gen_event:call(Sink, ?MODULE, flush). + +print_state(Sink) -> + gen_event:call(Sink, ?MODULE, print_state). + +print_bad_state(Sink) -> + gen_event:call(Sink, ?MODULE, print_bad_state). + has_line_numbers() -> %% are we R15 or greater - Rel = erlang:system_info(otp_release), - {match, [Major]} = re:run(Rel, "(?|(^R(\\d+)[A|B](|0(\\d)))|(^(\\d+)$))", [{capture, [2], list}]), - list_to_integer(Major) >= 15. + % this gets called a LOT - cache the answer + case erlang:get({?MODULE, has_line_numbers}) of + undefined -> + R = otp_version() >= 15, + erlang:put({?MODULE, has_line_numbers}, R), + R; + Bool -> + Bool + end. + +otp_version() -> + otp_version(erlang:system_info(otp_release)). + +otp_version([$R | Rel]) -> + {Ver, _} = string:to_integer(Rel), + Ver; +otp_version(Rel) -> + {Ver, _} = string:to_integer(Rel), + Ver. not_running_test() -> ?assertEqual({error, lager_not_running}, lager:log(info, self(), "not running")). @@ -126,6 +168,11 @@ ?assertEqual(0, count()) end }, + {"test sink not running", + fun() -> + ?assertEqual({error, {sink_not_configured, test}}, lager:log(test, info, self(), "~p", "not running")) + end + }, {"logging works", fun() -> lager:warning("test message"), @@ -136,6 +183,16 @@ ok end }, + {"unsafe logging works", + fun() -> + lager:warning_unsafe("test message"), + ?assertEqual(1, count()), + {Level, _Time, Message, _Metadata} = pop(), + ?assertMatch(Level, lager_util:level_to_num(warning)), + ?assertEqual("test message", Message), + ok + end + }, {"logging with arguments works", fun() -> lager:warning("test message ~p", [self()]), @@ -146,6 +203,16 @@ ok end }, + {"unsafe logging with args works", + fun() -> + lager:warning("test message ~p", [self()]), + ?assertEqual(1, count()), + {Level, _Time, Message,_Metadata} = pop(), + ?assertMatch(Level, lager_util:level_to_num(warning)), + ?assertEqual(lists:flatten(io_lib:format("test message ~p", [self()])), lists:flatten(Message)), + ok + end + }, {"logging works from inside a begin/end block", fun() -> ?assertEqual(0, count()), @@ -469,6 +536,39 @@ ok end }, + {"stopped trace stops and removes its event handler - default sink (gh#267)", + fun() -> + Sink = ?DEFAULT_SINK, + StartHandlers = gen_event:which_handlers(Sink), + {_, T0} = lager_config:get({Sink, loglevel}), + StartGlobal = lager_config:global_get(handlers), + ?assertEqual([], T0), + {ok, TestTrace1} = lager:trace_file("/tmp/test", [{a,b}]), + MidHandlers = gen_event:which_handlers(Sink), + {ok, TestTrace2} = lager:trace_file("/tmp/test", [{c,d}]), + MidHandlers = gen_event:which_handlers(Sink), + ?assertEqual(length(StartHandlers)+1, length(MidHandlers)), + MidGlobal = lager_config:global_get(handlers), + ?assertEqual(length(StartGlobal)+1, length(MidGlobal)), + {_, T1} = lager_config:get({Sink, loglevel}), + ?assertEqual(2, length(T1)), + ok = lager:stop_trace(TestTrace1), + {_, T2} = lager_config:get({Sink, loglevel}), + ?assertEqual(1, length(T2)), + ?assertEqual(length(StartHandlers)+1, length( + gen_event:which_handlers(Sink))), + + ?assertEqual(length(StartGlobal)+1, length(lager_config:global_get(handlers))), + ok = lager:stop_trace(TestTrace2), + EndHandlers = gen_event:which_handlers(?DEFAULT_SINK), + EndGlobal = lager_config:global_get(handlers), + {_, T3} = lager_config:get({Sink, loglevel}), + ?assertEqual([], T3), + ?assertEqual(StartHandlers, EndHandlers), + ?assertEqual(StartGlobal, EndGlobal), + ok + end + }, {"record printing works", fun() -> print_state(), @@ -545,6 +645,13 @@ ok end }, + {"unsafe messages really are not truncated",
View file
lager-2.1.0.tar.gz/test/pr_nested_record_test.erl -> lager-3.1.0.tar.gz/test/pr_nested_record_test.erl
Changed
@@ -2,13 +2,11 @@ -compile([{parse_transform, lager_transform}]). --record(a, {field1, field2}). --record(b, {field1, field2}). +-record(a, {field1 :: term(), field2 :: term()}). +-record(b, {field1 :: term() , field2 :: term()}). --ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). --endif. nested_record_test() -> A = #a{field1 = x, field2 = y},
View file
lager-3.1.0.tar.gz/test/pr_stacktrace_test.erl
Added
@@ -0,0 +1,55 @@ +-module(pr_stacktrace_test). + +-compile([{parse_transform, lager_transform}]). + +-include_lib("eunit/include/eunit.hrl"). + +make_throw() -> + throw({test, exception}). + +bad_arity() -> + lists:concat([], []). + +bad_arg() -> + integer_to_list(1.0). + +pr_stacktrace_throw_test() -> + Result = try + make_throw() + catch + Class:Reason -> + lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason}) + end, +ExpectedPart = " + pr_stacktrace_test:pr_stacktrace_throw_test/0 line 18 + pr_stacktrace_test:make_throw/0 line 8 +throw:{test,exception}", + ?assertNotEqual(0, string:str(Result, ExpectedPart)). + + +pr_stacktrace_bad_arg_test() -> + Result = try + bad_arg() + catch + Class:Reason -> + lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason}) + end, +ExpectedPart = " + pr_stacktrace_test:pr_stacktrace_bad_arg_test/0 line 32 + pr_stacktrace_test:bad_arg/0 line 14 +error:badarg", + ?assertNotEqual(0, string:str(Result, ExpectedPart)). + + +pr_stacktrace_bad_arity_test() -> + Result = try + bad_arity() + catch + Class:Reason -> + lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason}) + end, +ExpectedPart = " + pr_stacktrace_test:pr_stacktrace_bad_arity_test/0 line 46 + lists:concat([], []) +error:undef", + ?assertNotEqual(0, string:str(Result, ExpectedPart)). \ No newline at end of file
View file
lager-2.1.0.tar.gz/test/trunc_io_eqc.erl -> lager-3.1.0.tar.gz/test/trunc_io_eqc.erl
Changed
@@ -91,7 +91,7 @@ %% Generates a printable string gen_print_str() -> - ?LET(Xs, list(char()), [X || X <- Xs, io_lib:printable_list([X]), X /= $~, X < 255]). + ?LET(Xs, list(char()), [X || X <- Xs, io_lib:printable_list([X]), X /= $~, X < 256]). gen_print_bin() -> ?LET(Xs, gen_print_str(), list_to_binary(Xs)).
View file
lager-3.1.0.tar.gz/test/zzzz_gh280_crash.erl
Added
@@ -0,0 +1,33 @@ +%% @doc This test is named zzzz_gh280_crash because it has to be run first and tests are run in +%% reverse alphabetical order. +%% +%% The problem we are attempting to detect here is when log_mf_h is installed as a handler for error_logger +%% and lager starts up to replace the current handlers with its own. This causes a start up crash because +%% OTP error logging modules do not have any notion of a lager-style log level. +-module(zzzz_gh280_crash). +-compile(export_all). + +-include_lib("eunit/include/eunit.hrl"). + +gh280_crash_test() -> + application:stop(lager), + application:stop(goldrush), + + error_logger:tty(false), + %% see https://github.com/erlang/otp/blob/maint/lib/stdlib/src/log_mf_h.erl#L81 + %% for an explanation of the init arguments to log_mf_h + ok = gen_event:add_sup_handler(error_logger, log_mf_h, log_mf_h:init("/tmp", 10000, 5)), + lager:start(), + Result = receive + {gen_event_EXIT,log_mf_h,normal} -> + true; + {gen_event_EXIT,Handler,Reason} -> + {Handler,Reason}; + X -> + X + after 1000 -> + timeout + end, + ?assert(Result), + application:stop(lager), + application:stop(goldrush).
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.