Address #286. This will enable applications to
dynamically configure log sinks, provided they
have already instrumented the code via parse
transformation to use those sinks.
Previously, configuration would come from application:get_env/3 or
proplists:get_value/3. Now we standardize on a single format
for retrieving values from the environment or from a proplist.
This is, perhaps, not the most ideal setup. It still ignores other
sinks but does bring logging back online after the appropriate delay.
Signed-off-by: Brian L. Troutwine <brian.troutwine@adroll.com>
At this point in the work, the killer will correctly stop the
DEFAULT_SINK in the event of overload but our friend never comes back
up and lager stops working past this point.
Oops!
Error message:
=SUPERVISOR REPORT==== 10-Mar-2016::16:18:11 ===
Supervisor: {local,lager_handler_watcher_sup}
Context: child_terminated
Reason: killed
Offender: [{pid,<0.63.0>},
{id,lager_handler_watcher},
{mfargs,{lager_handler_watcher,start_link,undefined}},
{restart_type,temporary},
{shutdown,5000},
{child_type,worker}]
=SUPERVISOR REPORT==== 10-Mar-2016::16:18:11 ===
Supervisor: {local,lager_handler_watcher_sup}
Context: child_terminated
Reason: killed
Offender: [{pid,<0.59.0>},
{id,lager_handler_watcher},
{mfargs,{lager_handler_watcher,start_link,undefined}},
{restart_type,temporary},
{shutdown,5000},
{child_type,worker}]
=PROGRESS REPORT==== 10-Mar-2016::16:18:11 ===
supervisor: {local,lager_sup}
started: [{pid,<0.113.0>},
{id,lager},
{mfargs,{gen_event,start_link,[{local,lager_event}]}},
{restart_type,permanent},
{shutdown,5000},
{child_type,worker}]
Signed-off-by: Brian L. Troutwine <brian@troutwine.us>
During code review we decided that using Sink ++ '_lager_event'
would provide better isolation for gen_event names than
Sink ++ '_event' as we had been using up to this point.
For example a sink called 'audit' is now 'audit_lager_event'
than 'audit_event' which might clash with a user's predefined
own module or process name.
The default strategy is 'handle', for backwards compatibility,
and is set to that if otherwise undefined. Other strategies
include 'mirror' and 'ignore'.
Before when the error_logger was removed when lager starts up,
some functionality was chopped off, such as forwarding io to the
caller's group leader, this is supported with the strategy 'ignore'
and is similar to how the io system in erlang works traditionally.
Setting the 'mirror' strategy will essentially combine the other
two strategies such that the remote node reply is forwarded and also
handled locally. This is in some cases more in-line with what some
people might expect, efficiency may vary.
The traditional 'ignore' approach is more suitable and most likely
originally intended for embedded terminals where 'mirror'-ing the io
is largely unnecessary.
the default handlers defined at lager.app overwrites handlers defined previously by application:set_env(lager, handlers, ...) if lager application is started application:start(lager)
Adds transparent event stream processing and statistics.
A new 3-tuple trace is introduced as `{Key, Op, Value}`, but
for backwards compatibility `{Key, Val}` implies `=` for `Op`
and `{Key, '*'}` remains as is in the case of wildcards.
A simplified query tree module is generated which reduces
redundant selection conditions to minimize filtering overhead.
This is done via a combination of several things:
* Make the loglevel that triggers a sync configurable
* Make the delayed_write size and intervals configurable
* Make the interval at which external rotation is checked for
configurable
* Store the timestamp a lager_msg was created inside the lager_msg
To support these changes, several other things had to be modified:
* lager_msg:timestamp now returns a timestamp
* lager_msg:datetime was added to return the {date, time} of a message,
like lager_msg:timestamp used to
* The configuration syntax for file backends was changed to be of the
form {lager_file_backend, proplist()} and the old syntax was
deprecated
Additionally, the defaults for the check_interval was raised from
'always' to 1 second, and the sync_interval was changed from 2 seconds
to one second.
Implement a new config option error_logger_hwm, which is a number
representing how many messages per second we should log from the
error_logger. If that threshold is exceeded, messages will be discarded
for the remainder of that second.
This is only effective if lager itself can process the messages fast
enough to satisfy the threshold. If your threshold is 1000 and lager
itself is only writing 100 messages a second (because error messages are
causing fsyncs or whatever) you'll never exceed the threshold and drops
will never happen. Thus care needs to be taken when selecting this
feature.
Setting it low is not as bad as it might seem, because when using lager,
hopefully error_logger messages are unusual. In my testing, 50/second
with the default config seemed reasonable (which has 2 file backends
installed, both of which fsync on messages at error or above).
In normal operation, there's no need for log messages to be synchronous.
Its slower and introduces a global serialization point in the
application.
However, when in an overload condition, synchronous logging is good
because it limits each process to at most 1 log message in flight.
So, this change allows the gen_event at the core of lager to switch
modes depending on the size of the gen_event's mailbox. It should
provide better performance in the case of normal load, but it will also
prevent unbounded mailbox growth if an overload occurs.
The threshold at which the switch between async and sync is done is
configured via the 'async_threshold' app env var.
Add add_trace_to_loglevel_config and update_loglevel_config. These two
handle most of the updates to the loglevel config item, including the
update of the overall logging mask.
This makes minimum_loglevel private.
This doesn't change any behavior -- it just a tidy-up.