You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

292 lines
11 KiB

14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
12 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
13 years ago
12 years ago
  1. * Overview
  2. Lager (as in the beer) is a logging framework for Erlang. Its purpose is
  3. to provide a more traditional way to perform logging in an erlang application
  4. that plays nicely with traditional UNIX logging tools like logrotate and
  5. syslog. You can view the Lager EDocs [[http://basho.github.com/lager/][here]].
  6. [[http://travis-ci.org/basho/lager][Travis-CI]] :: [[https://secure.travis-ci.org/basho/lager.png]]
  7. * Features
  8. - Finer grained log levels (debug, info, notice, warning, error, critical,
  9. alert, emergency)
  10. - Logger calls are transformed using a parse transform to allow capturing
  11. Module/Function/Line/Pid information
  12. - When no handler is consuming a log level (eg. debug) no event is even sent
  13. to the log handler
  14. - Supports multiple backends, including console and file. More are planned.
  15. * Usage
  16. To use lager in your application, you need to define it as a rebar dep or have
  17. some other way of including it in erlang's path. You can then add the
  18. following option to the erlang compiler flags
  19. #+BEGIN_EXAMPLE
  20. {parse_transform, lager_transform}
  21. #+END_EXAMPLE
  22. Alternately, you can add it to the module you wish to compile with logging
  23. enabled:
  24. #+BEGIN_EXAMPLE
  25. -compile([{parse_transform, lager_transform}]).
  26. #+END_EXAMPLE
  27. Before logging any messages, you'll need to start the lager application. The
  28. lager module's start function takes care of loading and starting any dependencies
  29. lager requires.
  30. #+BEGIN_EXAMPLE
  31. lager:start().
  32. #+END_EXAMPLE
  33. Once you have built your code with lager and started the lager application,
  34. you can then generate log messages by doing the following:
  35. #+BEGIN_EXAMPLE
  36. lager:error("Some message")
  37. #+END_EXAMPLE
  38. Or:
  39. #+BEGIN_EXAMPLE
  40. lager:warning("Some message with a term: ~p", [Term])
  41. #+END_EXAMPLE
  42. The general form is lager:Severity() where Severity is one of the log levels
  43. mentioned above.
  44. * Configuration
  45. To configure lager's backends, you use an application variable (probably in
  46. your app.config):
  47. #+BEGIN_EXAMPLE
  48. {lager, [
  49. {handlers, [
  50. {lager_console_backend, info},
  51. {lager_file_backend, [
  52. {"error.log", error, 10485760, "$D0", 5},
  53. {"console.log", info, 10485760, "$D0", 5}
  54. ]}
  55. ]}
  56. ]}.
  57. #+END_EXAMPLE
  58. The available configuration options for each backend are listed in their
  59. module's documentation.
  60. * Custom Formatting
  61. All loggers have a default formatting that can be overriden. A formatter is any module that
  62. exports format(#lager_log_message{},Config#any()). It is specified as part of the configuration
  63. for the backend:
  64. #+BEGIN_EXAMPLE
  65. {lager, [
  66. {handlers, [
  67. {lager_console_backend, [info, {lager_default_formatter, [time," [",severity,"] ", message, "\n"]}},
  68. {lager_file_backend, [
  69. [{"error.log", error, 10485760, "$D0", 5,{lager_default_formatter,[date, " ", time," [",severity,"] ",pid, " ", message, "\n"]}],
  70. {"console.log", info, 10485760, "$D0", 5}
  71. ]}
  72. ]}
  73. ]}.
  74. #+END_EXAMPLE
  75. Included is lager_default_formatter. This provides a generic, default formatting for log messages using a "semi-iolist"
  76. as configuration. Any iolist allowed elements in the configuration are printed verbatim. Atoms in the configuration
  77. are treated as metadata properties and extracted from the log message.
  78. The metadata properties date,time, message, and severity will always exist.
  79. The properties pid, file, line, module, and function will always exist if the parser transform is used.
  80. #+BEGIN_EXAMPLE
  81. ["Foo"] -> "Foo", regardless of message content.
  82. [message] -> The content of the logged message, alone.
  83. [{pid,"Unknown Pid"}] -> "<?.?.?>" if pid is in the metadata, "Unknown Pid" if not.
  84. [{pid, ["My pid is ", pid], "Unknown Pid"}] -> if pid is in the metadata print "My pid is <?.?.?>", otherwise print "Unknown Pid"
  85. #+END_EXAMPLE
  86. Optionally, a tuple of {atom(),semi-iolist()}
  87. can be used. The atom will look up the property, but if not found it will use the semi-iolist() instead. These fallbacks
  88. can be nested or refer to other properties.
  89. #+BEGIN_EXAMPLE
  90. [{pid,"Unknown Pid"}] -> "<?.?.?>" if pid is in the metadata, "Unknown Pid" if not.
  91. [{server,[$(,{pid,"Unknown Server"},$)]}}] -> user provided server metadata, otherwise "(<?.?.?>)", otherwise "(Unknown Server)"
  92. #+END_EXAMPLE
  93. * Error logger integration
  94. Lager is also supplied with a error_logger handler module that translates
  95. traditional erlang error messages into a friendlier format and sends them into
  96. lager itself to be treated like a regular lager log call. To disable this, set
  97. the lager application variable `error_logger_redirect' to `false'.
  98. The error_logger handler will also log more complete error messages (protected
  99. with use of trunc_io) to a "crash log" which can be referred to for further
  100. information. The location of the crash log can be specified by the crash_log
  101. application variable. If undefined it is not written at all.
  102. Messages in the crash log are subject to a maximum message size which can be
  103. specified via the crash_log_msg_size application variable.
  104. * Runtime loglevel changes
  105. You can change the log level of any lager backend at runtime by doing the
  106. following:
  107. #+BEGIN_EXAMPLE
  108. lager:set_loglevel(lager_console_backend, debug).
  109. #+END_EXAMPLE
  110. Or, for the backend with multiple handles (files, mainly):
  111. #+BEGIN_EXAMPLE
  112. lager:set_loglevel(lager_file_backend, "console.log", debug).
  113. #+END_EXAMPLE
  114. Lager keeps track of the minium log level being used by any backend and
  115. supresses generation of messages lower than that level. This means that debug
  116. log messages, when no backend is consuming debug messages, are effectively
  117. free. A simple benchmark of doing 1 million debug log messages while the
  118. minimum threshold was above that takes less than half a second.
  119. * Internal log rotation
  120. Lager can rotate its own logs or have it done via an external process. To
  121. use internal rotation, use the last 3 values in the file backend's
  122. configuration tuple. For example
  123. #+BEGIN_EXAMPLE
  124. {"error.log", error, 10485760, "$D0", 5}
  125. #+END_EXAMPLE
  126. This tells lager to log error and above messages to "error.log" and to
  127. rotate the file at midnight or when it reaches 10mb, whichever comes first
  128. and to keep 5 rotated logs, in addition to the current one. Setting the
  129. count to 0 does not disable rotation, it instead rotates the file and keeps
  130. no previous versions around. To disable rotation set the size to 0 and the
  131. date to "".
  132. The "$D0" syntax is taken from the syntax newsyslog uses in newsyslog.conf.
  133. The relevant extract follows:
  134. #+BEGIN_EXAMPLE
  135. Day, week and month time format: The lead-in character
  136. for day, week and month specification is a `$'-sign.
  137. The particular format of day, week and month
  138. specification is: [Dhh], [Ww[Dhh]] and [Mdd[Dhh]],
  139. respectively. Optional time fields default to
  140. midnight. The ranges for day and hour specifications
  141. are:
  142. hh hours, range 0 ... 23
  143. w day of week, range 0 ... 6, 0 = Sunday
  144. dd day of month, range 1 ... 31, or the
  145. letter L or l to specify the last day of
  146. the month.
  147. Some examples:
  148. $D0 rotate every night at midnight
  149. $D23 rotate every day at 23:00 hr
  150. $W0D23 rotate every week on Sunday at 23:00 hr
  151. $W5D16 rotate every week on Friday at 16:00 hr
  152. $M1D0 rotate on the first day of every month at
  153. midnight (i.e., the start of the day)
  154. $M5D6 rotate on every 5th day of the month at
  155. 6:00 hr
  156. #+END_EXAMPLE
  157. To configure the crash log rotation, the following application variables are
  158. used:
  159. - crash_log_size
  160. - crash_log_date
  161. - crash_log_count
  162. See the .app.src file for further details.
  163. * Syslog Support
  164. Lager syslog output is provided as a separate application;
  165. [[https://github.com/basho/lager_syslog][lager_syslog]]. It is packaged as a
  166. separate application so Lager itself doesn't have an indirect dependancy on a
  167. port driver. Please see the lager_syslog README for configuration information.
  168. * AMQP Support
  169. Jon Brisbin has written a lager backend to send lager messages into AMQP, so
  170. you can aggregate logs from a cluster into a central point. You can find it
  171. under the [[https://github.com/jbrisbin/lager_amqp_backend][lager_amqp_backend]]
  172. project on github.
  173. * Loggly Support
  174. The team at [[https://www.kivra.com][KIVRA]] has written a lager backend to send
  175. lager messages into [[http://www.loggly.com][Loggly]]. You can find it
  176. under the [[https://github.com/kivra/lager_loggly][lager_loggly]]
  177. project on github.
  178. * Tracing
  179. Lager supports basic support for redirecting log messages based on log message
  180. attributes. Lager automatically captures the pid, module, function and line at the
  181. log message callsite. However, you can add any additional attributes you wish:
  182. #+BEGIN_EXAMPLE
  183. lager:warning([{request, RequestID},{vhost, Vhost}], "Permission denied to ~s", [User])
  184. #+END_EXAMPLE
  185. Then, in addition to the default trace attributes, you'll be able to trace
  186. based on request or vhost:
  187. #+BEGIN_EXAMPLE
  188. lager:trace_file("logs/example.com.error", [{vhost, "example.com"}], error)
  189. #+END_EXAMPLE
  190. You can also omit the final argument, and the loglevel will default to
  191. 'debug'.
  192. Tracing to the console is similar:
  193. #+BEGIN_EXAMPLE
  194. lager:trace_console([{request, 117}])
  195. #+END_EXAMPLE
  196. In the above example, the loglevel is omitted, but it can be specified as the
  197. second argument if desired.
  198. You can also specify multiple expressions in a filter, or use the '*' atom as
  199. a wildcard to match any message that has that attribute, regardless of its
  200. value.
  201. Tracing to an existing logfile is also supported, if you wanted to log
  202. warnings from a particular module to the default error.log:
  203. #+BEGIN_EXAMPLE
  204. lager:trace_file("log/error.log", [{module, mymodule}], warning)
  205. #+END_EXAMPLE
  206. To view the active log backends and traces, you can use the lager:status()
  207. function. To clear all active traces, you can use lager:clear_all_traces().
  208. To delete a specific trace, store a handle for the trace when you create it,
  209. that you later pass to lager:stop_trace/1:
  210. #+BEGIN_EXAMPLE
  211. {ok, Trace} = lager:trace_file("log/error.log", [{module, mymodule}]),
  212. ...
  213. lager:stop_trace(Trace)
  214. #+END_EXAMPLE
  215. Tracing to a pid is somewhat of a special case, since a pid is not a
  216. data-type that serializes well. To trace by pid, use the pid as a string:
  217. #+BEGIN_EXAMPLE
  218. lager:trace_console([{pid, "<0.410.0>"}])
  219. #+END_EXAMPLE
  220. * Setting the truncation limit at compile-time
  221. Lager defaults to truncating messages at 4096 bytes, you can alter this by
  222. using the {lager_truncation_size, X} option. In rebar, you can add it to
  223. erl_opts:
  224. #+BEGIN_EXAMPLE
  225. {erl_opts, [{parse_transform, lager_transform}, {lager_truncation_size, 1024}]}.
  226. #+END_EXAMPLE
  227. You can also pass it to erlc, if you prefer:
  228. #+BEGIN_EXAMPLE
  229. erlc -pa lager/ebin +'{parse_transform, lager_transform}' +'{lager_truncation_size, 1024}' file.erl
  230. #+END_EXAMPLE