• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

include/H05-Oct-2016-12682

priv/H05-Oct-2016-131109

src/H03-May-2022-7,5265,956

test/H05-Oct-2016-2,6812,260

.travis.ymlH A D05-Oct-2016124 109

LICENSEH A D05-Oct-20169.9 KiB179150

MakefileH A D05-Oct-2016357 2214

README.mdH A D05-Oct-201624.4 KiB708556

TODOH A D05-Oct-201682 43

dialyzer.ignore-warningsH A D05-Oct-2016226 65

rebar.configH A D03-May-20221.7 KiB5849

tools.mkH A D05-Oct-20165.6 KiB15087

README.md

1Overview
2--------
3Lager (as in the beer) is a logging framework for Erlang. Its purpose is
4to provide a more traditional way to perform logging in an erlang application
5that plays nicely with traditional UNIX logging tools like logrotate and
6syslog.
7
8  [Travis-CI](http://travis-ci.org/basho/lager) :: ![Travis-CI](https://secure.travis-ci.org/basho/lager.png)
9
10Features
11--------
12* Finer grained log levels (debug, info, notice, warning, error, critical,
13  alert, emergency)
14* Logger calls are transformed using a parse transform to allow capturing
15  Module/Function/Line/Pid information
16* When no handler is consuming a log level (eg. debug) no event is sent
17  to the log handler
18* Supports multiple backends, including console and file.
19* Supports multiple sinks
20* Rewrites common OTP error messages into more readable messages
21* Support for pretty printing records encountered at compile time
22* Tolerant in the face of large or many log messages, won't out of memory the node
23* Optional feature to bypass log size truncation ("unsafe")
24* Supports internal time and date based rotation, as well as external rotation tools
25* Syslog style log level comparison flags
26* Colored terminal output (requires R16+)
27* Map support (requires 17+)
28* Optional load shedding by setting a high water mark to kill (and reinstall)
29  a sink after a configurable cool down timer
30
31Usage
32-----
33To use lager in your application, you need to define it as a rebar dep or have
34some other way of including it in Erlang's path. You can then add the
35following option to the erlang compiler flags:
36
37```erlang
38{parse_transform, lager_transform}
39```
40
41Alternately, you can add it to the module you wish to compile with logging
42enabled:
43
44```erlang
45-compile([{parse_transform, lager_transform}]).
46```
47
48Before logging any messages, you'll need to start the lager application. The
49lager module's `start` function takes care of loading and starting any dependencies
50lager requires.
51
52```erlang
53lager:start().
54```
55
56You can also start lager on startup with a switch to `erl`:
57
58```erlang
59erl -pa path/to/lager/ebin -s lager
60```
61
62Once you have built your code with lager and started the lager application,
63you can then generate log messages by doing the following:
64
65```erlang
66lager:error("Some message")
67```
68
69  Or:
70
71```erlang
72lager:warning("Some message with a term: ~p", [Term])
73```
74
75The general form is `lager:Severity()` where `Severity` is one of the log levels
76mentioned above.
77
78Configuration
79-------------
80To configure lager's backends, you use an application variable (probably in
81your app.config):
82
83```erlang
84{lager, [
85  {log_root, "/var/log/hello"},
86  {handlers, [
87    {lager_console_backend, info},
88    {lager_file_backend, [{file, "error.log"}, {level, error}]},
89    {lager_file_backend, [{file, "console.log"}, {level, info}]}
90  ]}
91]}.
92```
93
94```log_root``` variable is optional, by default file paths are relative to CWD.
95
96The available configuration options for each backend are listed in their
97module's documentation.
98
99Sinks
100-----
101Lager has traditionally supported a single sink (implemented as a
102`gen_event` manager) named `lager_event` to which all backends were
103connected.
104
105Lager now supports extra sinks; each sink can have different
106sync/async message thresholds and different backends.
107
108### Sink configuration
109
110To use multiple sinks (beyond the built-in sink of lager and lager_event), you
111need to:
112
1131. Setup rebar.config
1142. Configure the backends in app.config
115
116#### Names
117
118Each sink has two names: one atom to be used like a module name for
119sending messages, and that atom with `_lager_event` appended for backend
120configuration.
121
122This reflects the legacy behavior: `lager:info` (or `critical`, or
123`debug`, etc) is a way of sending a message to a sink named
124`lager_event`. Now developers can invoke `audit:info` or
125`myCompanyName:debug` so long as the corresponding `audit_lager_event` or
126`myCompanyName_lager_event` sinks are configured.
127
128#### rebar.config
129
130In `rebar.config` for the project that requires lager, include a list
131of sink names (without the `_lager_event` suffix) in `erl_opts`:
132
133`{lager_extra_sinks, [audit]}`
134
135#### Runtime requirements
136
137To be useful, sinks must be configured at runtime with backends.
138
139In `app.config` for the project that requires lager, for example,
140extend the lager configuration to include an `extra_sinks` tuple with
141backends (aka "handlers") and optionally `async_threshold` and
142`async_threshold_window` values (see **Overload Protection**
143below). If async values are not configured, no overload protection
144will be applied on that sink.
145
146```erlang
147[{lager, [
148          {log_root, "/tmp"},
149
150          %% Default handlers for lager/lager_event
151          {handlers, [
152                      {lager_console_backend, info},
153                      {lager_file_backend, [{file, "error.log"}, {level, error}]},
154                      {lager_file_backend, [{file, "console.log"}, {level, info}]}
155                     ]},
156
157          %% Any other sinks
158          {extra_sinks,
159           [
160            {audit_lager_event,
161             [{handlers,
162               [{lager_file_backend,
163                 [{file, "sink1.log"},
164                  {level, info}
165                 ]
166                }]
167              },
168              {async_threshold, 500},
169              {async_threshold_window, 50}]
170            }]
171          }
172         ]
173 }
174].
175```
176
177Custom Formatting
178-----------------
179All loggers have a default formatting that can be overriden.  A formatter is any module that
180exports `format(#lager_log_message{},Config#any())`.  It is specified as part of the configuration
181for the backend:
182
183```erlang
184{lager, [
185  {handlers, [
186    {lager_console_backend, [info, {lager_default_formatter, [time," [",severity,"] ", message, "\n"]}]},
187    {lager_file_backend, [{file, "error.log"}, {level, error}, {formatter, lager_default_formatter},
188      {formatter_config, [date, " ", time," [",severity,"] ",pid, " ", message, "\n"]}]},
189    {lager_file_backend, [{file, "console.log"}, {level, info}]}
190  ]}
191]}.
192```
193
194Included is `lager_default_formatter`.  This provides a generic, default
195formatting for log messages using a structure similar to Erlang's
196[iolist](http://learnyousomeerlang.com/buckets-of-sockets#io-lists) which we
197call "semi-iolist":
198
199* Any traditional iolist elements in the configuration are printed verbatim.
200* Atoms in the configuration are treated as placeholders for lager metadata and
201  extracted from the log message.
202    * The placeholders `date`, `time`, `message`, `sev` and `severity` will always exist.
203    * `sev` is an abbreviated severity which is interpreted as a capitalized
204      single letter encoding of the severity level (e.g. `'debug'` -> `$D`)
205    * The placeholders `pid`, `file`, `line`, `module`, `function`, and `node`
206      will always exist if the parse transform is used.
207    * Applications can define their own metadata placeholder.
208    * A tuple of `{atom(), semi-iolist()}` allows for a fallback for
209      the atom placeholder. If the value represented by the atom
210      cannot be found, the semi-iolist will be interpreted instead.
211    * A tuple of `{atom(), semi-iolist(), semi-iolist()}` represents a
212      conditional operator: if a value for the atom placeholder can be
213      found, the first semi-iolist will be output; otherwise, the
214      second will be used.
215
216Examples:
217
218```
219["Foo"] -> "Foo", regardless of message content.
220[message] -> The content of the logged message, alone.
221[{pid,"Unknown Pid"}] -> "<?.?.?>" if pid is in the metadata, "Unknown Pid" if not.
222[{pid, ["My pid is ", pid], ["Unknown Pid"]}] -> if pid is in the metadata print "My pid is <?.?.?>", otherwise print "Unknown Pid"
223[{server,{pid, ["(", pid, ")"], ["(Unknown Server)"]}}] -> user provided server metadata, otherwise "(<?.?.?>)", otherwise "(Unknown Server)"
224```
225
226Error logger integration
227------------------------
228Lager is also supplied with a `error_logger` handler module that translates
229traditional erlang error messages into a friendlier format and sends them into
230lager itself to be treated like a regular lager log call. To disable this, set
231the lager application variable `error_logger_redirect` to `false`.
232You can also disable reformatting for OTP and Cowboy messages by setting variable
233`error_logger_format_raw` to `true`.
234
235The `error_logger` handler will also log more complete error messages (protected
236with use of `trunc_io`) to a "crash log" which can be referred to for further
237information. The location of the crash log can be specified by the crash_log
238application variable. If set to `false` it is not written at all.
239
240Messages in the crash log are subject to a maximum message size which can be
241specified via the `crash_log_msg_size` application variable.
242
243Messages from `error_logger` will be redirected to `error_logger_lager_event` sink
244if it is defined so it can be redirected to another log file.
245
246For example:
247
248```
249[{lager, [
250         {extra_sinks,
251          [
252           {error_logger_lager_event,
253            [{handlers, [
254              {lager_file_backend, [{file, "error_logger.log"}, {level, info}]}]
255              }]
256           }]
257           }]
258}].
259```
260will send all `error_logger` messages to `error_logger.log` file.
261
262Overload Protection
263-------------------
264
265### Asynchronous mode
266
267Prior to lager 2.0, the `gen_event` at the core of lager operated purely in
268synchronous mode. Asynchronous mode is faster, but has no protection against
269message queue overload. As of lager 2.0, the `gen_event` takes a hybrid
270approach. it polls its own mailbox size and toggles the messaging between
271synchronous and asynchronous depending on mailbox size.
272
273```erlang
274{async_threshold, 20},
275{async_threshold_window, 5}
276```
277
278This will use async messaging until the mailbox exceeds 20 messages, at which
279point synchronous messaging will be used, and switch back to asynchronous, when
280size reduces to `20 - 5 = 15`.
281
282If you wish to disable this behaviour, simply set it to `undefined`. It defaults
283to a low number to prevent the mailbox growing rapidly beyond the limit and causing
284problems. In general, lager should process messages as fast as they come in, so getting
28520 behind should be relatively exceptional anyway.
286
287If you want to limit the number of messages per second allowed from `error_logger`,
288which is a good idea if you want to weather a flood of messages when lots of
289related processes crash, you can set a limit:
290
291```erlang
292{error_logger_hwm, 50}
293```
294
295It is probably best to keep this number small.
296
297### Sink Killer
298
299In some high volume situations, it may be preferable to drop all pending log
300messages instead of letting them drain over time.
301
302If you prefer, you may choose to use the sink killer to shed load. In this
303operational mode, if the `gen_event` mailbox exceeds a configurable
304high water mark, the sink will be killed and reinstalled after a
305configurable cool down time.
306
307You can configure this behavior by using these configuration directives:
308
309```erlang
310{killer_hwm, 1000},
311{killer_reinstall_after, 5000}
312```
313
314This means if the sink's mailbox size exceeds 1000 messages, kill the
315entire sink and reload it after 5000 milliseconds. This behavior can
316also be installed into alternative sinks if desired.
317
318By default, the manager killer *is not installed* into any sink. If
319the `killer_reinstall_after` cool down time is not specified it defaults
320to 5000.
321
322"Unsafe"
323--------
324The unsafe code pathway bypasses the normal lager formatting code and uses the
325same code as error_logger in OTP. This provides a marginal speedup to your logging
326code (we measured between 0.5-1.3% improvement during our benchmarking; others have
327reported better improvements.)
328
329This is a **dangerous** feature. It *will not* protect you against
330large log messages - large messages can kill your application and even your
331Erlang VM dead due to memory exhaustion as large terms are copied over and
332over in a failure cascade.  We strongly recommend that this code pathway
333only be used by log messages with a well bounded upper size of around 500 bytes.
334
335If there's any possibility the log messages could exceed that limit, you should
336use the normal lager message formatting code which will provide the appropriate
337size limitations and protection against memory exhaustion.
338
339If you want to format an unsafe log message, you may use the severity level (as
340usual) followed by `_unsafe`. Here's an example:
341
342```erlang
343lager:info_unsafe("The quick brown ~s jumped over the lazy ~s", ["fox", "dog"]).
344```
345
346Runtime loglevel changes
347------------------------
348You can change the log level of any lager backend at runtime by doing the
349following:
350
351```erlang
352lager:set_loglevel(lager_console_backend, debug).
353```
354
355  Or, for the backend with multiple handles (files, mainly):
356
357```erlang
358lager:set_loglevel(lager_file_backend, "console.log", debug).
359```
360
361Lager keeps track of the minimum log level being used by any backend and
362suppresses generation of messages lower than that level. This means that debug
363log messages, when no backend is consuming debug messages, are effectively
364free. A simple benchmark of doing 1 million debug log messages while the
365minimum threshold was above that takes less than half a second.
366
367Syslog style loglevel comparison flags
368--------------------------------------
369In addition to the regular log level names, you can also do finer grained masking
370of what you want to log:
371
372```
373info - info and higher (>= is implicit)
374=debug - only the debug level
375!=info - everything but the info level
376<=notice - notice and below
377<warning - anything less than warning
378```
379
380These can be used anywhere a loglevel is supplied, although they need to be either
381a quoted atom or a string.
382
383Internal log rotation
384---------------------
385Lager can rotate its own logs or have it done via an external process. To
386use internal rotation, use the `size`, `date` and `count` values in the file
387backend's config:
388
389```erlang
390[{file, "error.log"}, {level, error}, {size, 10485760}, {date, "$D0"}, {count, 5}]
391```
392
393This tells lager to log error and above messages to `error.log` and to
394rotate the file at midnight or when it reaches 10mb, whichever comes first,
395and to keep 5 rotated logs in addition to the current one. Setting the
396count to 0 does not disable rotation, it instead rotates the file and keeps
397no previous versions around. To disable rotation set the size to 0 and the
398date to "".
399
400The `$D0` syntax is taken from the syntax newsyslog uses in newsyslog.conf.
401The relevant extract follows:
402
403```
404Day, week and month time format: The lead-in character
405for day, week and month specification is a `$'-sign.
406The particular format of day, week and month
407specification is: [Dhh], [Ww[Dhh]] and [Mdd[Dhh]],
408respectively.  Optional time fields default to
409midnight.  The ranges for day and hour specifications
410are:
411
412  hh      hours, range 0 ... 23
413  w       day of week, range 0 ... 6, 0 = Sunday
414  dd      day of month, range 1 ... 31, or the
415          letter L or l to specify the last day of
416          the month.
417
418Some examples:
419  $D0     rotate every night at midnight
420  $D23    rotate every day at 23:00 hr
421  $W0D23  rotate every week on Sunday at 23:00 hr
422  $W5D16  rotate every week on Friday at 16:00 hr
423  $M1D0   rotate on the first day of every month at
424          midnight (i.e., the start of the day)
425  $M5D6   rotate on every 5th day of the month at
426          6:00 hr
427```
428
429To configure the crash log rotation, the following application variables are
430used:
431* `crash_log_size`
432* `crash_log_date`
433* `crash_log_count`
434
435See the `.app.src` file for further details.
436
437Syslog Support
438--------------
439Lager syslog output is provided as a separate application:
440[lager_syslog](https://github.com/basho/lager_syslog). It is packaged as a
441separate application so lager itself doesn't have an indirect dependency on a
442port driver. Please see the `lager_syslog` README for configuration information.
443
444Older Backends
445--------------
446Lager 2.0 changed the backend API, there are various 3rd party backends for
447lager available, but they may not have been updated to the new API. As they
448are updated, links to them can be re-added here.
449
450Exception Pretty Printing
451----------------------
452
453```erlang
454try
455    foo()
456catch
457    Class:Reason ->
458        lager:error(
459            "~nStacktrace:~s",
460            [lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason})])
461end.
462```
463
464Record Pretty Printing
465----------------------
466Lager's parse transform will keep track of any record definitions it encounters
467and store them in the module's attributes. You can then, at runtime, print any
468record a module compiled with the lager parse transform knows about by using the
469`lager:pr/2` function, which takes the record and the module that knows about the record:
470
471```erlang
472lager:info("My state is ~p", [lager:pr(State, ?MODULE)])
473```
474
475Often, `?MODULE` is sufficent, but you can obviously substitute that for a literal module name.
476`lager:pr` also works from the shell.
477
478Colored terminal output
479-----------------------
480If you have Erlang R16 or higher, you can tell lager's console backend to be colored. Simply
481add to lager's application environment config:
482
483```erlang
484{colored, true}
485```
486
487If you don't like the default colors, they are also configurable; see
488the `.app.src` file for more details.
489
490The output will be colored from the first occurrence of the atom color
491in the formatting configuration. For example:
492
493```erlang
494{lager_console_backend, [info, {lager_default_formatter, [time, color, " [",severity,"] ", message, "\e[0m\r\n"]}]}
495```
496
497This will make the entire log message, except time, colored. The
498escape sequence before the line break is needed in order to reset the
499color after each log message.
500
501Tracing
502-------
503Lager supports basic support for redirecting log messages based on log message
504attributes. Lager automatically captures the pid, module, function and line at the
505log message callsite. However, you can add any additional attributes you wish:
506
507```erlang
508lager:warning([{request, RequestID},{vhost, Vhost}], "Permission denied to ~s", [User])
509```
510
511Then, in addition to the default trace attributes, you'll be able to trace
512based on request or vhost:
513
514```erlang
515lager:trace_file("logs/example.com.error", [{vhost, "example.com"}], error)
516```
517
518To persist metadata for the life of a process, you can use `lager:md/1` to store metadata
519in the process dictionary:
520
521```erlang
522lager:md([{zone, forbidden}])
523```
524
525Note that `lager:md` will *only* accept a list of key/value pairs keyed by atoms.
526
527You can also omit the final argument, and the loglevel will default to
528`debug`.
529
530Tracing to the console is similar:
531
532```erlang
533lager:trace_console([{request, 117}])
534```
535
536In the above example, the loglevel is omitted, but it can be specified as the
537second argument if desired.
538
539You can also specify multiple expressions in a filter, or use the `*` atom as
540a wildcard to match any message that has that attribute, regardless of its
541value.
542
543Tracing to an existing logfile is also supported (but see **Multiple
544sink support** below):
545
546```erlang
547lager:trace_file("log/error.log", [{module, mymodule}, {function, myfunction}], warning)
548```
549
550To view the active log backends and traces, you can use the `lager:status()`
551function. To clear all active traces, you can use `lager:clear_all_traces()`.
552
553To delete a specific trace, store a handle for the trace when you create it,
554that you later pass to `lager:stop_trace/1`:
555
556```erlang
557{ok, Trace} = lager:trace_file("log/error.log", [{module, mymodule}]),
558...
559lager:stop_trace(Trace)
560```
561
562Tracing to a pid is somewhat of a special case, since a pid is not a
563data-type that serializes well. To trace by pid, use the pid as a string:
564
565```erlang
566lager:trace_console([{pid, "<0.410.0>"}])
567```
568
569As of lager 2.0, you can also use a 3 tuple while tracing, where the second
570element is a comparison operator. The currently supported comparison operators
571are:
572
573* `<` - less than
574* `=` - equal to
575* `>` - greater than
576
577```erlang
578lager:trace_console([{request, '>', 117}, {request, '<', 120}])
579```
580
581Using `=` is equivalent to the 2-tuple form.
582
583### Multiple sink support
584
585If using multiple sinks, there are limitations on tracing that you
586should be aware of.
587
588Traces are specific to a sink, which can be specified via trace
589filters:
590
591```erlang
592lager:trace_file("log/security.log", [{sink, audit_event}, {function, myfunction}], warning)
593```
594
595If no sink is thus specified, the default lager sink will be used.
596
597This has two ramifications:
598
599* Traces cannot intercept messages sent to a different sink.
600* Tracing to a file already opened via `lager:trace_file` will only be
601  successful if the same sink is specified.
602
603The former can be ameliorated by opening multiple traces; the latter
604can be fixed by rearchitecting lager's file backend, but this has not
605been tackled.
606
607### Traces from configuration
608
609Lager supports starting traces from its configuration file. The keyword
610to define them is `traces`, followed by a proplist of tuples that define
611a backend handler and zero or more filters in a required list,
612followed by an optional message severity level.
613
614An example looks like this:
615
616```erlang
617{lager, [
618  {handlers, [...]},
619  {traces, [
620    %% handler,                         filter,                message level (defaults to debug if not given)
621    {lager_console_backend,             [{module, foo}],       info },
622    {{lager_file_backend, "trace.log"}, [{request, '>', 120}], error},
623    {{lager_file_backend, "event.log"}, [{module, bar}]             } %% implied debug level here
624  ]}
625]}.
626```
627
628In this example, we have three traces. One using the console backend, and two
629using the file backend. If the message severity level is left out, it defaults
630to `debug` as in the last file backend example.
631
632The `traces` keyword works on alternative sinks too but the same limitations
633and caveats noted above apply.
634
635**IMPORTANT**: You **must** define a severity level in all lager releases
636up to and including 3.1.0 or previous. The 2-tuple form wasn't added until
6373.2.0.
638
639Setting the truncation limit at compile-time
640--------------------------------------------
641Lager defaults to truncating messages at 4096 bytes, you can alter this by
642using the `{lager_truncation_size, X}` option. In rebar, you can add it to
643`erl_opts`:
644
645```erlang
646{erl_opts, [{parse_transform, lager_transform}, {lager_truncation_size, 1024}]}.
647```
648
649You can also pass it to `erlc`, if you prefer:
650
651```
652erlc -pa lager/ebin +'{parse_transform, lager_transform}' +'{lager_truncation_size, 1024}' file.erl
653```
654
6553.x Changelog
656-------------
6573.2.2 - 22 September 2016
658
659    * Bugfix: Backwards-compatibility fix for `{crash_log, undefined}` (#371)
660    * Fix documentation/README to reflect the preference for using `false`
661      as the `crash_log` setting value rather than `undefined` to indicate
662      that the crash log should not be written (#364)
663    * Bugfix: Backwards-compatibility fix for `lager_file_backend` "legacy"
664      configuration format (#374)
665
6663.2.1 - 10 June 2016
667
668    * Bugfix: Recent `get_env` changes resulted in launch failure (#355)
669    * OTP: Support typed records for Erlang 19.0 (#361)
670
6713.2.0 - 08 April 2016
672
673    * Feature: Optional sink killer to shed load when mailbox size exceeds a
674      configurable high water mark (#346)
675    * Feature: Export `configure_sink/2` so users may dynamically configure
676      previously setup and parse transformed sinks from their own code. (#342)
677    * Feature: Re-enable Travis CI and update .travis.yml (#340)
678    * Bugfix: Fix test race conditions for Travis CI (#344)
679    * Bugfix: Add the atom 'none' to the log_level() type so downstream
680      users won't get dialyzer failures if they use the 'none' log level. (#343)
681    * Bugfix: Fix typo in documentation. (#341)
682    * Bugfix: Fix OTP 18 test failures due to `warning_map/0` response
683      change. (#337)
684    * Bugfix: Make sure traces that use the file backend work correctly
685      when specified in lager configuration. (#336)
686    * Bugfix: Use `lager_app:get_env/3` for R15 compatibility. (#335)
687    * Bugfix: Make sure lager uses `id` instead of `name` when reporting
688      supervisor children failures. (The atom changed in OTP in 2014.) (#334)
689    * Bugfix: Make lager handle improper iolists (#327)
690
6913.1.0 - 27 January 2016
692
693    * Feature: API calls to a rotate handler, sink or all.  This change
694      introduces a new `rotate` message for 3rd party lager backends; that's
695      why this is released as a new minor version number. (#311)
696
6973.0.3 - 27 January 2016
698
699    * Feature: Pretty printer for human readable stack traces (#298)
700    * Feature: Make error reformatting optional (#305)
701    * Feature: Optional and explicit sink for error_logger messages (#303)
702    * Bugfix: Always explicitly close a file after its been rotated (#316)
703    * Bugfix: If a relative path already contains the log root, do not add it again (#317)
704    * Bugfix: Configure and start extra sinks before traces are evaluated (#307)
705    * Bugfix: Stop and remove traces correctly (#306)
706    * Bugfix: A byte value of 255 is valid for Unicode (#300)
707    * Dependency: Bump to goldrush 0.1.8 (#313)
708