rewrite from lager
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

934 líneas
34 KiB

hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
hace 4 años
  1. Overview
  2. --------
  3. eRum is a Erlang logger. 基于lager3.9.0 rewrite
  4. Features
  5. --------
  6. * Finer grained log levels (debug, info, notice, warning, error, critical, alert, emergency)
  7. * Logger calls are transformed using a parse transform to allow capturing Module/Function/Line/Pid information
  8. * When no handler is consuming a log level (eg. debug) no event is sent to the log handler
  9. * Supports multiple backends, including console and file.
  10. * Supports multiple sinks
  11. * Rewrites common OTP error messages into more readable messages
  12. * Support for pretty printing records encountered at compile time
  13. * Tolerant in the face of large or many log messages, won't out of memory the node
  14. * Optional feature to bypass log size truncation ("unsafe")
  15. * Supports internal time and date based rotation, as well as external rotation tools
  16. * Syslog style log level comparison flags
  17. * Colored terminal output
  18. * Optional load shedding by setting a high water mark to kill (and reinstall)
  19. a sink after a configurable cool down timer
  20. * rewrite term format fun, it's more efficient
  21. Usage
  22. -----
  23. To use eRum in your application, you need to define it as a rebar dep or have some other way of including it in Erlang's
  24. path. You can then add the following option to the erlang compiler flags:
  25. ```erlang
  26. {parse_transform, rumTransform}
  27. ```
  28. Alternately, you can add it to the module you wish to compile with logging enabled:
  29. ```erlang
  30. -compile([{parse_transform, rumTransform}]).
  31. ```
  32. Before logging any messages, you'll need to start the eRum application. The eRum module's `start` function takes care of
  33. loading and starting any dependencies eRum requires.
  34. ```erlang
  35. eRum:start().
  36. ```
  37. You can also start eRum on startup with a switch to `erl`:
  38. ```erlang
  39. erl -pa path/to/eRum/ebin -s eRum
  40. ```
  41. Once you have built your code with eRum and started the eRum application, you can then generate log messages by doing
  42. the following:
  43. ```erlang
  44. eRum:error("Some message")
  45. ```
  46. Or:
  47. ```erlang
  48. eRum:warning("Some message with a term: ~p", [Term])
  49. ```
  50. The general form is `eRum:Severity()` where `Severity` is one of the log levels mentioned above.
  51. Configuration
  52. -------------
  53. To configure eRum's backends, you use an application variable (probably in your app.config):
  54. ```erlang
  55. {eRum, [
  56. {log_root, "/var/log/hello"},
  57. {handlers, [
  58. {lager_console_backend, [{level, info}]},
  59. {lager_file_backend, [{file, "error.log"}, {level, error}]},
  60. {lager_file_backend, [{file, "console.log"}, {level, info}]}
  61. ]}
  62. ]}.
  63. ```
  64. ```log_root``` variable is optional, by default file paths are relative to CWD.
  65. The available configuration options for each backend are listed in their module's documentation.
  66. Sinks
  67. -----
  68. Lager has traditionally supported a single sink (implemented as a
  69. `gen_event` manager) named `lager_event` to which all backends were connected.
  70. Lager now supports extra sinks; each sink can have different sync/async message thresholds and different backends.
  71. ### Sink configuration
  72. To use multiple sinks (beyond the built-in sink of lager and lager_event), you need to:
  73. 1. Setup rebar.config
  74. 2. Configure the backends in app.config
  75. #### Names
  76. Each sink has two names: one atom to be used like a module name for sending messages, and that atom with `_lager_event`
  77. appended for backend configuration.
  78. This reflects the legacy behavior: `lager:info` (or `critical`, or
  79. `debug`, etc) is a way of sending a message to a sink named
  80. `lager_event`. Now developers can invoke `audit:info` or
  81. `myCompanyName:debug` so long as the corresponding `audit_lager_event` or
  82. `myCompanyName_lager_event` sinks are configured.
  83. #### rebar.config
  84. In `rebar.config` for the project that requires lager, include a list of sink names (without the `_lager_event` suffix)
  85. in `erl_opts`:
  86. `{lager_extra_sinks, [audit]}`
  87. #### Runtime requirements
  88. To be useful, sinks must be configured at runtime with backends.
  89. In `app.config` for the project that requires lager, for example, extend the lager configuration to include
  90. an `extra_sinks` tuple with backends (aka "handlers") and optionally `async_threshold` and
  91. `async_threshold_window` values (see **Overload Protection**
  92. below). If async values are not configured, no overload protection will be applied on that sink.
  93. ```erlang
  94. [{lager, [
  95. {log_root, "/tmp"},
  96. %% Default handlers for lager/lager_event
  97. {handlers, [
  98. {lager_console_backend, [{level, info}]},
  99. {lager_file_backend, [{file, "error.log"}, {level, error}]},
  100. {lager_file_backend, [{file, "console.log"}, {level, info}]}
  101. ]},
  102. %% Any other sinks
  103. {extra_sinks,
  104. [
  105. {audit_lager_event,
  106. [{handlers,
  107. [{lager_file_backend,
  108. [{file, "sink1.log"},
  109. {level, info}
  110. ]
  111. }]
  112. },
  113. {async_threshold, 500},
  114. {async_threshold_window, 50}]
  115. }]
  116. }
  117. ]
  118. }
  119. ].
  120. ```
  121. Custom Formatting
  122. -----------------
  123. All loggers have a default formatting that can be overriden. A formatter is any module that
  124. exports `format(#lager_log_message{},Config#any())`. It is specified as part of the configuration for the backend:
  125. ```erlang
  126. {lager, [
  127. {handlers, [
  128. {lager_console_backend, [{level, info}, {formatter, lager_default_formatter},
  129. {formatter_config, [time, " [",severity, "] ", message, "\n"]}]},
  130. {lager_file_backend, [{file, "error.log"}, {level, error}, {formatter, lager_default_formatter},
  131. {formatter_config, [date, " ", time, " [", severity, "] ",pid, " ", message, "\n"]}]},
  132. {lager_file_backend, [{file, "console.log"}, {level, info}]}
  133. ]}
  134. ]}.
  135. ```
  136. Included is `lager_default_formatter`. This provides a generic, default formatting for log messages using a structure
  137. similar to Erlang's
  138. [iolist](http://learnyousomeerlang.com/buckets-of-sockets#io-lists) which we call "semi-iolist":
  139. * Any traditional iolist elements in the configuration are printed verbatim.
  140. * Atoms in the configuration are treated as placeholders for lager metadata and extracted from the log message.
  141. * The placeholders `date`, `time`, `message`, `sev` and `severity` will always exist.
  142. * `sev` is an abbreviated severity which is interpreted as a capitalized single letter encoding of the severity
  143. level (e.g. `'debug'` -> `$D`)
  144. * The placeholders `pid`, `file`, `line`, `module`, `function`, and `node`
  145. will always exist if the parse transform is used.
  146. * The placeholder `application` may exist if the parse transform is used. It is dependent on finding the
  147. applications `app.src` file.
  148. * If the error logger integration is used, the placeholder `pid`
  149. will always exist and the placeholder `name` may exist.
  150. * Applications can define their own metadata placeholder.
  151. * A tuple of `{atom(), semi-iolist()}` allows for a fallback for the atom placeholder. If the value represented by
  152. the atom cannot be found, the semi-iolist will be interpreted instead.
  153. * A tuple of `{atom(), semi-iolist(), semi-iolist()}` represents a conditional operator: if a value for the atom
  154. placeholder can be found, the first semi-iolist will be output; otherwise, the second will be used.
  155. * A tuple of `{pterm, atom()}` will attempt to lookup the value of the specified atom from the
  156. [persistent_term](http://erlang.org/doc/man/persistent_term.html)
  157. feature added in OTP 21.2. The default value is `""`. The default value will be used if the key cannot be found or
  158. if this formatting term is specified on an OTP release before OTP 21.
  159. * A tuple of `{pterm, atom(), semi-iolist()}` will attempt to lookup the value of the specified atom from the
  160. persistent_term feature added in OTP 21.2. The default value is the specified semi-iolist(). The default value
  161. will be used if the key cannot be found or the if this formatting term is specified on an OTP release before OTP
  162. 21.
  163. Examples:
  164. ```
  165. ["Foo"] -> "Foo", regardless of message content.
  166. [message] -> The content of the logged message, alone.
  167. [{pid,"Unknown Pid"}] -> "<?.?.?>" if pid is in the metadata, "Unknown Pid" if not.
  168. [{pid, ["My pid is ", pid], ["Unknown Pid"]}] -> if pid is in the metadata print "My pid is <?.?.?>", otherwise print "Unknown Pid"
  169. [{server,{pid, ["(", pid, ")"], ["(Unknown Server)"]}}] -> user provided server metadata, otherwise "(<?.?.?>)", otherwise "(Unknown Server)"
  170. [{pterm, pterm_key, <<"undefined">>}] -> if a value for 'pterm_key' is found in OTP 21 (or later) persistent_term storage it is used, otherwise "undefined"
  171. ```
  172. Universal time
  173. --------------
  174. By default, lager formats timestamps as local time for whatever computer generated the log message.
  175. To make lager use UTC timestamps, you can set the `sasl` application's
  176. `utc_log` configuration parameter to `true` in your application configuration file.
  177. Example:
  178. ```
  179. %% format log timestamps as UTC
  180. [{sasl, [{utc_log, true}]}].
  181. ```
  182. Error logger integration
  183. ------------------------
  184. Lager is also supplied with a `error_logger` handler module that translates traditional erlang error messages into a
  185. friendlier format and sends them into lager itself to be treated like a regular lager log call. To disable this, set the
  186. lager application variable `error_logger_redirect` to `false`. You can also disable reformatting for OTP and Cowboy
  187. messages by setting variable
  188. `error_logger_format_raw` to `true`.
  189. If you installed your own handler(s) into `error_logger`, you can tell lager to leave it alone by using
  190. the `error_logger_whitelist` environment variable with a list of handlers to allow.
  191. ```
  192. {error_logger_whitelist, [my_handler]}
  193. ```
  194. The `error_logger` handler will also log more complete error messages (protected with use of `trunc_io`) to a "crash
  195. log" which can be referred to for further information. The location of the crash log can be specified by the `crash_log`
  196. application variable. If set to `false` it is not written at all.
  197. Messages in the crash log are subject to a maximum message size which can be specified via the `crash_log_msg_size`
  198. application variable.
  199. Messages from `error_logger` will be redirected to `error_logger_lager_event` sink if it is defined so it can be
  200. redirected to another log file.
  201. For example:
  202. ```
  203. [{lager, [
  204. {extra_sinks,
  205. [
  206. {error_logger_lager_event,
  207. [{handlers, [
  208. {lager_file_backend, [{file, "error_logger.log"}, {level, info}]}]
  209. }]
  210. }]
  211. }]
  212. }].
  213. ```
  214. will send all `error_logger` messages to `error_logger.log` file.
  215. Overload Protection
  216. -------------------
  217. ### Asynchronous mode
  218. Prior to lager 2.0, the `gen_event` at the core of lager operated purely in synchronous mode. Asynchronous mode is
  219. faster, but has no protection against message queue overload. As of lager 2.0, the `gen_event` takes a hybrid approach.
  220. it polls its own mailbox size and toggles the messaging between synchronous and asynchronous depending on mailbox size.
  221. ```erlang
  222. {async_threshold, 20},
  223. {async_threshold_window, 5}
  224. ```
  225. This will use async messaging until the mailbox exceeds 20 messages, at which point synchronous messaging will be used,
  226. and switch back to asynchronous, when size reduces to `20 - 5 = 15`.
  227. If you wish to disable this behaviour, simply set `async_threshold` to `undefined`. It defaults to a low number to
  228. prevent the mailbox growing rapidly beyond the limit and causing problems. In general, lager should process messages as
  229. fast as they come in, so getting 20 behind should be relatively exceptional anyway.
  230. If you want to limit the number of messages per second allowed from `error_logger`, which is a good idea if you want to
  231. weather a flood of messages when lots of related processes crash, you can set a limit:
  232. ```erlang
  233. {error_logger_hwm, 50}
  234. ```
  235. It is probably best to keep this number small.
  236. ### Event queue flushing
  237. When the high-water mark is exceeded, lager can be configured to flush all event notifications in the message queue.
  238. This can have unintended consequences for other handlers in the same event manager (in e.g. the `error_logger`), as
  239. events they rely on may be wrongly discarded. By default, this behavior is enabled, but can be controlled, for
  240. the `error_logger` via:
  241. ```erlang
  242. {error_logger_flush_queue, true | false}
  243. ```
  244. or for a specific sink, using the option:
  245. ```erlang
  246. {flush_queue, true | false}
  247. ```
  248. If `flush_queue` is true, a message queue length threshold can be set, at which messages will start being discarded. The
  249. default threshold is `0`, meaning that if `flush_queue` is true, messages will be discarded if the high-water mark is
  250. exceeded, regardless of the length of the message queue. The option to control the threshold is, for `error_logger`:
  251. ```erlang
  252. {error_logger_flush_threshold, 1000}
  253. ```
  254. and for sinks:
  255. ```erlang
  256. {flush_threshold, 1000}
  257. ```
  258. ### Sink Killer
  259. In some high volume situations, it may be preferable to drop all pending log messages instead of letting them drain over
  260. time.
  261. If you prefer, you may choose to use the sink killer to shed load. In this operational mode, if the `gen_event` mailbox
  262. exceeds a configurable high water mark, the sink will be killed and reinstalled after a configurable cool down time.
  263. You can configure this behavior by using these configuration directives:
  264. ```erlang
  265. {killer_hwm, 1000},
  266. {killer_reinstall_after, 5000}
  267. ```
  268. This means if the sink's mailbox size exceeds 1000 messages, kill the entire sink and reload it after 5000 milliseconds.
  269. This behavior can also be installed into alternative sinks if desired.
  270. By default, the manager killer *is not installed* into any sink. If the `killer_reinstall_after` cool down time is not
  271. specified it defaults to 5000.
  272. "Unsafe"
  273. --------
  274. The unsafe code pathway bypasses the normal lager formatting code and uses the same code as error_logger in OTP. This
  275. provides a marginal speedup to your logging code (we measured between 0.5-1.3% improvement during our benchmarking;
  276. others have reported better improvements.)
  277. This is a **dangerous** feature. It *will not* protect you against large log messages - large messages can kill your
  278. application and even your Erlang VM dead due to memory exhaustion as large terms are copied over and over in a failure
  279. cascade. We strongly recommend that this code pathway only be used by log messages with a well bounded upper size of
  280. around 500 bytes.
  281. If there's any possibility the log messages could exceed that limit, you should use the normal lager message formatting
  282. code which will provide the appropriate size limitations and protection against memory exhaustion.
  283. If you want to format an unsafe log message, you may use the severity level (as usual) followed by `_unsafe`. Here's an
  284. example:
  285. ```erlang
  286. lager:info_unsafe("The quick brown ~s jumped over the lazy ~s", ["fox", "dog"]).
  287. ```
  288. Runtime loglevel changes
  289. ------------------------
  290. You can change the log level of any lager backend at runtime by doing the following:
  291. ```erlang
  292. lager:set_loglevel(lager_console_backend, debug).
  293. ```
  294. Or, for the backend with multiple handles (files, mainly):
  295. ```erlang
  296. lager:set_loglevel(lager_file_backend, "console.log", debug).
  297. ```
  298. Lager keeps track of the minimum log level being used by any backend and suppresses generation of messages lower than
  299. that level. This means that debug log messages, when no backend is consuming debug messages, are effectively free. A
  300. simple benchmark of doing 1 million debug log messages while the minimum threshold was above that takes less than half a
  301. second.
  302. Syslog style loglevel comparison flags
  303. --------------------------------------
  304. In addition to the regular log level names, you can also do finer grained masking of what you want to log:
  305. ```
  306. info - info and higher (>= is implicit)
  307. =debug - only the debug level
  308. !=info - everything but the info level
  309. <=notice - notice and below
  310. <warning - anything less than warning
  311. ```
  312. These can be used anywhere a loglevel is supplied, although they need to be either a quoted atom or a string.
  313. Internal log rotation
  314. ---------------------
  315. Lager can rotate its own logs or have it done via an external process. To use internal rotation, use the `size`, `date`
  316. and `count` values in the file backend's config:
  317. ```erlang
  318. [{file, "error.log"}, {level, error}, {size, 10485760}, {date, "$D0"}, {count, 5}]
  319. ```
  320. This tells lager to log error and above messages to `error.log` and to rotate the file at midnight or when it reaches
  321. 10mb, whichever comes first, and to keep 5 rotated logs in addition to the current one. Setting the count to 0 does not
  322. disable rotation, it instead rotates the file and keeps no previous versions around. To disable rotation set the size to
  323. 0 and the date to "".
  324. The `$D0` syntax is taken from the syntax newsyslog uses in newsyslog.conf. The relevant extract follows:
  325. ```
  326. Day, week and month time format: The lead-in character
  327. for day, week and month specification is a `$'-sign.
  328. The particular format of day, week and month
  329. specification is: [Dhh], [Ww[Dhh]] and [Mdd[Dhh]],
  330. respectively. Optional time fields default to
  331. midnight. The ranges for day and hour specifications
  332. are:
  333. hh hours, range 0 ... 23
  334. w day of week, range 0 ... 6, 0 = Sunday
  335. dd day of month, range 1 ... 31, or the
  336. letter L or l to specify the last day of
  337. the month.
  338. Some examples:
  339. $D0 rotate every night at midnight
  340. $D23 rotate every day at 23:00 hr
  341. $W0D23 rotate every week on Sunday at 23:00 hr
  342. $W5D16 rotate every week on Friday at 16:00 hr
  343. $M1D0 rotate on the first day of every month at
  344. midnight (i.e., the start of the day)
  345. $M5D6 rotate on every 5th day of the month at
  346. 6:00 hr
  347. ```
  348. On top of the day, week and month time format from newsyslog, hour specification is added from
  349. PR [#420](https://github.com/erlang-lager/lager/pull/420)
  350. ```
  351. Format of hour specification is : [Hmm]
  352. The range for minute specification is:
  353. mm minutes, range 0 ... 59
  354. Some examples:
  355. $H00 rotate every hour at HH:00
  356. $D12H30 rotate every day at 12:30
  357. $W0D0H0 rotate every week on Sunday at 00:00
  358. ```
  359. To configure the crash log rotation, the following application variables are used:
  360. * `crash_log_size`
  361. * `crash_log_date`
  362. * `crash_log_count`
  363. * `crash_log_rotator`
  364. See the `.app.src` file for further details.
  365. Custom Log Rotation
  366. -------------------
  367. Custom log rotator could be configured with option for `lager_file_backend`
  368. ```erlang
  369. {rotator, lager_rotator_default}
  370. ```
  371. The module should provide the following callbacks as `lager_rotator_behaviour`
  372. ```erlang
  373. %% @doc Create a log file
  374. -callback(create_logfile(Name :: list(), Buffer :: {integer(), integer()} | any()) ->
  375. {ok, {FD :: file:io_device(), Inode :: integer(), Size :: integer()}} | {error, any()}).
  376. %% @doc Open a log file
  377. -callback(open_logfile(Name :: list(), Buffer :: {integer(), integer()} | any()) ->
  378. {ok, {FD :: file:io_device(), Inode :: integer(), Size :: integer()}} | {error, any()}).
  379. %% @doc Ensure reference to current target, could be rotated
  380. -callback(ensure_logfile(Name :: list(), FD :: file:io_device(), Inode :: integer(),
  381. Buffer :: {integer(), integer()} | any()) ->
  382. {ok, {FD :: file:io_device(), Inode :: integer(), Size :: integer()}} | {error, any()}).
  383. %% @doc Rotate the log file
  384. -callback(rotate_logfile(Name :: list(), Count :: integer()) ->
  385. ok).
  386. ```
  387. Syslog Support
  388. --------------
  389. Lager syslog output is provided as a separate application:
  390. [lager_syslog](https://github.com/erlang-lager/lager_syslog). It is packaged as a separate application so lager itself
  391. doesn't have an indirect dependency on a port driver. Please see the `lager_syslog` README for configuration
  392. information.
  393. Other Backends
  394. --------------
  395. There are lots of them! Some connect log messages to AMQP, various logging analytic
  396. services ([bunyan](https://github.com/Vagabond/lager_bunyan_formatter),
  397. [loggly](https://github.com/kivra/lager_loggly), etc), and
  398. more. [Looking on hex](https://hex.pm/packages?_utf8=✓&search=lager&sort=recent_downloads) or using "lager BACKEND"
  399. where "BACKEND" is your preferred log solution on your favorite search engine is a good starting point.
  400. Exception Pretty Printing
  401. ----------------------
  402. Up to OTP 20:
  403. ```erlang
  404. try
  405. foo()
  406. catch
  407. Class:Reason ->
  408. lager:error(
  409. "~nStacktrace:~s",
  410. [lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason})])
  411. end .
  412. ```
  413. On OTP 21+:
  414. ```erlang
  415. try
  416. foo()
  417. catch
  418. Class:Reason:Stacktrace ->
  419. lager:error(
  420. "~nStacktrace:~s",
  421. [lager:pr_stacktrace(Stacktrace, {Class, Reason})])
  422. end .
  423. ```
  424. Record Pretty Printing
  425. ----------------------
  426. Lager's parse transform will keep track of any record definitions it encounters and store them in the module's
  427. attributes. You can then, at runtime, print any record a module compiled with the lager parse transform knows about by
  428. using the
  429. `lager:pr/2` function, which takes the record and the module that knows about the record:
  430. ```erlang
  431. lager:info("My state is ~p", [lager:pr(State, ?MODULE)])
  432. ```
  433. Often, `?MODULE` is sufficent, but you can obviously substitute that for a literal module name.
  434. `lager:pr` also works from the shell.
  435. Colored terminal output
  436. -----------------------
  437. If you have Erlang R16 or higher, you can tell lager's console backend to be colored. Simply add to lager's application
  438. environment config:
  439. ```erlang
  440. {colored, true}
  441. ```
  442. If you don't like the default colors, they are also configurable; see the `.app.src` file for more details.
  443. The output will be colored from the first occurrence of the atom color in the formatting configuration. For example:
  444. ```erlang
  445. {lager_console_backend, [{level, info}, {formatter, lager_default_formatter},
  446. {formatter_config, [time, color, " [", severity, "] ", message, "\e[0m\r\n"]}]]}
  447. ```
  448. This will make the entire log message, except time, colored. The escape sequence before the line break is needed in
  449. order to reset the color after each log message.
  450. Tracing
  451. -------
  452. Lager supports basic support for redirecting log messages based on log message attributes. Lager automatically captures
  453. the pid, module, function and line at the log message callsite. However, you can add any additional attributes you wish:
  454. ```erlang
  455. lager:warning([{request, RequestID}, {vhost, Vhost}], "Permission denied to ~s", [User])
  456. ```
  457. Then, in addition to the default trace attributes, you'll be able to trace based on request or vhost:
  458. ```erlang
  459. lager:trace_file("logs/example.com.error", [{vhost, "example.com"}], error)
  460. ```
  461. To persist metadata for the life of a process, you can use `lager:md/1` to store metadata in the process dictionary:
  462. ```erlang
  463. lager:md([{zone, forbidden}])
  464. ```
  465. Note that `lager:md` will *only* accept a list of key/value pairs keyed by atoms.
  466. You can also omit the final argument, and the loglevel will default to
  467. `debug`.
  468. Tracing to the console is similar:
  469. ```erlang
  470. lager:trace_console([{request, 117}])
  471. ```
  472. In the above example, the loglevel is omitted, but it can be specified as the second argument if desired.
  473. You can also specify multiple expressions in a filter, or use the `*` atom as a wildcard to match any message that has
  474. that attribute, regardless of its value. You may also use the special value `!` to mean, only select if this key is **
  475. not** present.
  476. Tracing to an existing logfile is also supported (but see **Multiple sink support** below):
  477. ```erlang
  478. lager:trace_file("log/error.log", [{module, mymodule}, {function, myfunction}], warning)
  479. ```
  480. To view the active log backends and traces, you can use the `lager:status()`
  481. function. To clear all active traces, you can use `lager:clear_all_traces()`.
  482. To delete a specific trace, store a handle for the trace when you create it, that you later pass
  483. to `lager:stop_trace/1`:
  484. ```erlang
  485. {ok, Trace} = lager:trace_file("log/error.log", [{module, mymodule}]),
  486. ...
  487. lager:stop_trace(Trace)
  488. ```
  489. Tracing to a pid is somewhat of a special case, since a pid is not a data-type that serializes well. To trace by pid,
  490. use the pid as a string:
  491. ```erlang
  492. lager:trace_console([{pid, "<0.410.0>"}])
  493. ```
  494. ### Filter expressions
  495. As of lager 3.3.1, you can also use a 3 tuple while tracing where the second element is a comparison operator. The
  496. currently supported comparison operators are:
  497. * `<` - less than
  498. * `=<` - less than or equal
  499. * `=` - equal to
  500. * `!=` - not equal to
  501. * `>` - greater than
  502. * `>=` - greater than or equal
  503. ```erlang
  504. lager:trace_console([{request, '>', 117}, {request, '<', 120}])
  505. ```
  506. Using `=` is equivalent to the 2-tuple form.
  507. ### Filter composition
  508. As of lager 3.3.1 you may also use the special filter composition keys of
  509. `all` or `any`. For example the filter example above could be expressed as:
  510. ```erlang
  511. lager:trace_console([{all, [{request, '>', 117}, {request, '<', 120}]}])
  512. ```
  513. `any` has the effect of "OR style" logical evaluation between filters; `all`
  514. means "AND style" logical evaluation between filters. These compositional filters expect a list of additional filter
  515. expressions as their values.
  516. ### Null filters
  517. The `null` filter has a special meaning. A filter of `{null, false}` acts as a black hole; nothing is passed through. A
  518. filter of `{null, true}` means
  519. *everything* passes through. No other values for the null filter are valid and will be rejected.
  520. ### Multiple sink support
  521. If using multiple sinks, there are limitations on tracing that you should be aware of.
  522. Traces are specific to a sink, which can be specified via trace filters:
  523. ```erlang
  524. lager:trace_file("log/security.log", [{sink, audit_event}, {function, myfunction}], warning)
  525. ```
  526. If no sink is thus specified, the default lager sink will be used.
  527. This has two ramifications:
  528. * Traces cannot intercept messages sent to a different sink.
  529. * Tracing to a file already opened via `lager:trace_file` will only be successful if the same sink is specified.
  530. The former can be ameliorated by opening multiple traces; the latter can be fixed by rearchitecting lager's file
  531. backend, but this has not been tackled.
  532. ### Traces from configuration
  533. Lager supports starting traces from its configuration file. The keyword to define them is `traces`, followed by a
  534. proplist of tuples that define a backend handler and zero or more filters in a required list, followed by an optional
  535. message severity level.
  536. An example looks like this:
  537. ```erlang
  538. {lager, [
  539. {handlers, [...]},
  540. {traces, [
  541. %% handler, filter, message level (defaults to debug if not given)
  542. {lager_console_backend, [{module, foo}], info},
  543. {{lager_file_backend, "trace.log"}, [{request, '>', 120}], error},
  544. {{lager_file_backend, "event.log"}, [{module, bar}]} %% implied debug level here
  545. ]}
  546. ]}.
  547. ```
  548. In this example, we have three traces. One using the console backend, and two using the file backend. If the message
  549. severity level is left out, it defaults to `debug` as in the last file backend example.
  550. The `traces` keyword works on alternative sinks too but the same limitations and caveats noted above apply.
  551. **IMPORTANT**: You **must** define a severity level in all lager releases up to and including 3.1.0 or previous. The
  552. 2-tuple form wasn't added until 3.2.0.
  553. Setting dynamic metadata at compile-time
  554. ----------------------------------------
  555. Lager supports supplying metadata from external sources by registering a callback function. This metadata is also
  556. persistent across processes even if the process dies.
  557. In general use you won't need to use this feature. However it is useful in situations such as:
  558. * Tracing information provided by
  559. [seq_trace](http://erlang.org/doc/man/seq_trace.html)
  560. * Contextual information about your application
  561. * Persistent information which isn't provided by the default placeholders
  562. * Situations where you would have to set the metadata before every logging call
  563. You can add the callbacks by using the `{lager_parse_transform_functions, X}`
  564. option. It is only available when using `parse_transform`. In rebar, you can add it to `erl_opts` as below:
  565. ```erlang
  566. {erl_opts, [{parse_transform, lager_transform},
  567. {lager_function_transforms,
  568. [
  569. %% Placeholder Resolve type Callback tuple
  570. {metadata_placeholder, on_emit, {module_name, function_name}},
  571. {other_metadata_placeholder, on_log, {module_name, function_name}}
  572. ]}]}.
  573. ```
  574. The first atom is the placeholder atom used for the substitution in your custom formatter.
  575. See [Custom Formatting](#custom-formatting) for more information.
  576. The second atom is the resolve type. This specify the callback to resolve at the time of the message being emitted or at
  577. the time of the logging call. You have to specify either the atom `on_emit` or `on_log`. There is not a 'right' resolve
  578. type to use, so please read the uses/caveats of each and pick the option which fits your requirements best.
  579. `on_emit`:
  580. * The callback functions are not resolved until the message is emitted by the backend.
  581. * If the callback function cannot be resolved, not loaded or produces unhandled errors then `undefined` will be
  582. returned.
  583. * Since the callback function is dependent on a process, there is the chance that message will be emitted after the
  584. dependent process has died resulting in `undefined` being returned. This process can also be your own process
  585. `on_log`:
  586. * The callback functions are resolved regardless whether the message is
  587. emitted or not
  588. * If the callback function cannot be resolved or not loaded the errors are not handled by lager itself.
  589. * Any potential errors in callback should be handled in the callback function itself.
  590. * Because the function is resolved at log time there should be less chance of the dependent process dying before you can
  591. resolve it, especially if you are logging from the app which contains the callback.
  592. The third element is the callback to your function consisting of a tuple in the form `{Module Function}`. The callback
  593. should look like the following regardless if using `on_emit` or `on_log`:
  594. * It should be exported
  595. * It should takes no arguments e.g. has an arity of 0
  596. * It should return any traditional iolist elements or the atom `undefined`
  597. * For errors generated within your callback see the resolve type documentation above.
  598. If the callback returns `undefined` then it will follow the same fallback and conditional operator rules as documented
  599. in the
  600. [Custom Formatting](#custom-formatting) section.
  601. This example would work with `on_emit` but could be unsafe to use with
  602. `on_log`. If the call failed in `on_emit` it would default to `undefined`, however with `on_log` it would error.
  603. ```erlang
  604. -export([my_callback/0]).
  605. my_callback() ->
  606. my_app_serv:call('some options').
  607. ```
  608. This example would be to safe to work with both `on_emit` and `on_log`
  609. ```erlang
  610. -export([my_callback/0]).
  611. my_callback() ->
  612. try my_app_serv:call('some options') of
  613. Result ->
  614. Result
  615. catch
  616. _ ->
  617. %% You could define any traditional iolist elements you wanted here
  618. undefined
  619. end.
  620. ```
  621. Note that the callback can be any Module:Function/0. It does not have be part of your application. For example you could
  622. use `cpu_sup:avg1/0` as your
  623. callback function like so `{cpu_avg1, on_emit, {cpu_sup, avg1}}`
  624. Examples:
  625. ```erlang
  626. -export([reductions/0]).
  627. reductions() ->
  628. proplists:get_value(reductions, erlang:process_info(self())).
  629. ```
  630. ```erlang
  631. -export([seq_trace/0]).
  632. seq_trace() ->
  633. case seq_trace:get_token(label) of
  634. {label, TraceLabel} ->
  635. TraceLabel;
  636. _ ->
  637. undefined
  638. end.
  639. ```
  640. **IMPORTANT**: Since `on_emit` relies on function calls injected at the point where a log message is emitted, your
  641. logging performance (ops/sec)
  642. will be impacted by what the functions you call do and how much latency they may introduce. This impact will even
  643. greater with `on_log` since the calls are injected at the point a message is logged.
  644. Setting the truncation limit at compile-time
  645. --------------------------------------------
  646. Lager defaults to truncating messages at 4096 bytes, you can alter this by using the `{lager_truncation_size, X}`
  647. option. In rebar, you can add it to
  648. `erl_opts`:
  649. ```erlang
  650. {erl_opts, [{parse_transform, lager_transform}, {lager_truncation_size, 1024}]}.
  651. ```
  652. You can also pass it to `erlc`, if you prefer:
  653. ```
  654. erlc -pa lager/ebin +'{parse_transform, lager_transform}' +'{lager_truncation_size, 1024}' file.erl
  655. ```
  656. Suppress applications and supervisors start/stop logs
  657. -----------------------------------------------------
  658. If you don't want to see supervisors and applications start/stop logs in debug level of your application, you can use
  659. these configs to turn it off:
  660. ```erlang
  661. {lager, [{suppress_application_start_stop, true},
  662. {suppress_supervisor_start_stop, true}]}
  663. ```
  664. Sys debug functions
  665. --------------------
  666. Lager provides an integrated way to use sys 'debug functions'. You can install a debug function in a target process by
  667. doing
  668. ```erlang
  669. lager:install_trace(Pid, notice).
  670. ```
  671. You can also customize the tracing somewhat:
  672. ```erlang
  673. lager:install_trace(Pid, notice, [{count, 100}, {timeout, 5000}, {format_string, "my trace event ~p ~p"]}).
  674. ```
  675. The trace options are currently:
  676. * timeout - how long the trace stays installed: `infinity` (the default) or a millisecond timeout
  677. * count - how many trace events to log: `infinity` (default) or a positive number
  678. * format_string - the format string to log the event with. *Must* have 2 format specifiers for the 2 parameters
  679. supplied.
  680. This will, on every 'system event' for an OTP process (usually inbound messages, replies and state changes) generate a
  681. lager message at the specified log level.
  682. You can remove the trace when you're done by doing:
  683. ```erlang
  684. lager:remove_trace(Pid).
  685. ```
  686. If you want to start an OTP process with tracing enabled from the very beginning, you can do something like this:
  687. ```erlang
  688. gen_server:start_link(mymodule, [], [{debug, [{install, {fun lager:trace_func/3, lager:trace_state(undefined, notice, [])}}]}]).
  689. ```
  690. The third argument to the trace_state function is the Option list documented above.
  691. Console output to another group leader process
  692. ----------------------------------------------
  693. If you want to send your console output to another group_leader (typically on another node) you can provide
  694. a `{group_leader, Pid}` argument to the console backend. This can be combined with another console config option, `id`
  695. and gen_event's `{Module, ID}` to allow remote tracing of a node to standard out via nodetool:
  696. ```erlang
  697. GL = erlang:group_leader(),
  698. Node = node(GL),
  699. lager_app:start_handler(lager_event, {lager_console_backend, Node},
  700. [{group_leader, GL}, {level, none}, {id, {lager_console_backend, Node}}]),
  701. case lager:trace({lager_console_backend, Node}, Filter, Level) of
  702. ...
  703. ```
  704. In the above example, the code is assumed to be running via a `nodetool rpc`
  705. invocation so that the code is executing on the Erlang node, but the group_leader is that of the reltool node (eg.
  706. appname_maint_12345@127.0.0.1).
  707. If you intend to use tracing with this feature, make sure the second parameter to start_handler and the `id` parameter
  708. match. Thus when the custom group_leader process exits, lager will remove any associated traces for that handler.