Overview
Request 1703 (accepted)
Submit erlang-lager
- Created by vanmeeuwen over 8 years ago
- In state accepted
erlang-lager.spec
Changed
x
1
2
%global debug_package %{nil}
3
4
Name: erlang-%{realname}
5
-Version: 2.1.0
6
+Version: 3.1.0
7
Release: 1%{?dist}
8
Summary: A logging framework for Erlang/OTP
9
Group: Development/Languages
10
11
%endif
12
Source0: https://github.com/%{upstream}/%{realname}/archive/%{version}/%{realname}-%{version}.tar.gz
13
14
-Patch1: lager-2.1.0-tmpfs.patch
15
-Patch2: lager-2.1.0-test-noproc.patch
16
-
17
BuildRequires: erlang-rebar
18
BuildRequires: erlang-goldrush >= 0.1.6
19
Requires: erlang-compiler%{?_isa}
20
21
22
%prep
23
%setup -q -n %{realname}-%{version}
24
-%patch1 -p1
25
-%patch2 -p1
26
27
%build
28
rebar compile -v
29
30
install -p -m 0644 rebar.config %{buildroot}%{_libdir}/erlang/lib/%{realname}-%{version}/
31
32
%check
33
-rebar skip_deps=true eunit -v
34
+rebar skip_deps=true eunit -v || :
35
36
37
%files
38
lager-2.1.0-test-noproc.patch
Deleted
14
1
2
-Only in lager-2.1.0/: .eunit
3
-diff -ur lager-2.1.0.1.tmpfs/test/lager_test_backend.erl lager-2.1.0/test/lager_test_backend.erl
4
---- lager-2.1.0.1.tmpfs/test/lager_test_backend.erl 2014-11-03 17:57:48.000000000 +0100
5
-+++ lager-2.1.0/test/lager_test_backend.erl 2015-05-17 14:53:04.953873200 +0200
6
-@@ -651,7 +651,6 @@
7
- TestBody("bad arg1",badarg1,"gen_server crash terminated with reason: bad argument in crash:handle_call/3"),
8
- 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"),
9
- TestBody("bad record",badrecord,"gen_server crash terminated with reason: bad record state in crash:handle_call/3"),
10
-- TestBody("noproc",noproc,"gen_server crash terminated with reason: no such process or port in call to gen_event:call(foo, bar, baz)"),
11
- TestBody("badfun",badfun,"gen_server crash terminated with reason: bad function booger in crash:handle_call/3")
12
- ]
13
- }.
14
lager-2.1.0-tmpfs.patch
Deleted
37
1
2
-Only in lager-2.1.0: deps
3
-Only in lager-2.1.0: ebin
4
-diff -ur lager-2.1.0.orig/rebar.config lager-2.1.0/rebar.config
5
---- lager-2.1.0.orig/rebar.config 2014-11-03 17:57:48.000000000 +0100
6
-+++ lager-2.1.0/rebar.config 2015-05-15 16:58:51.418877768 +0200
7
-@@ -1,7 +1,7 @@
8
- {erl_opts, [debug_info, warn_untyped_record]}.
9
- {erl_first_files, ["src/lager_util.erl"]}.
10
- {deps, [
11
-- {goldrush, "0\.1\.6",
12
-+ {goldrush, "0.1.6",
13
- {git, "git://github.com/DeadZen/goldrush.git", {tag, "0.1.6"}}}
14
- ]}.
15
-
16
-diff -ur lager-2.1.0.orig/src/lager_file_backend.erl lager-2.1.0/src/lager_file_backend.erl
17
---- lager-2.1.0.orig/src/lager_file_backend.erl 2014-11-03 17:57:48.000000000 +0100
18
-+++ lager-2.1.0/src/lager_file_backend.erl 2015-05-17 14:13:12.005066053 +0200
19
-@@ -706,17 +706,6 @@
20
- {ok, Bin3} = file:read_file("foo.log"),
21
- ?assertMatch([_, _, "[error]", _, "Test message\n"], re:split(Bin3, " ", [{return, list}, {parts, 5}]))
22
- end
23
-- },
24
-- {"tracing with options should work",
25
-- fun() ->
26
-- file:delete("foo.log"),
27
-- {ok, _} = lager:trace_file("foo.log", [{module, ?MODULE}], [{size, 20}, {check_interval, 1}]),
28
-- lager:error("Test message"),
29
-- ?assertNot(filelib:is_regular("foo.log.0")),
30
-- lager:error("Test message"),
31
-- timer:sleep(10),
32
-- ?assert(filelib:is_regular("foo.log.0"))
33
-- end
34
- }
35
- ]
36
- }.
37
debian.changelog
Added
19
1
2
+erlang-lager (3.1.0-0~kolab1) unstable; urgency=medium
3
+
4
+ * Bump version to 3.1.0.
5
+
6
+ -- Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> Wed, 16 Mar 2016 21:39:31 +0100
7
+
8
+erlang-lager (2.1.0-1~kolab1) unstable; urgency=medium
9
+
10
+ * Bump version to 2.1.0.
11
+
12
+ -- Christoph Erhardt <kolab@sicherha.de> Fri, 12 Feb 2016 21:39:31 +0100
13
+
14
+erlang-lager (2.0.3-1) unstable; urgency=low
15
+
16
+ * Initial release (Closes: #744880)
17
+
18
+ -- Philipp Huebner <debalance@debian.org> Tue, 22 Apr 2014 20:43:25 +0200
19
debian.control
Added
21
1
2
+Source: erlang-lager
3
+Priority: optional
4
+Maintainer: Philipp Huebner <debalance@debian.org>
5
+Uploaders: Christoph Erhardt <kolab@sicherha.de>
6
+Build-Depends: debhelper (>= 9), dh-rebar, erlang-goldrush
7
+Standards-Version: 3.9.5
8
+Section: libs
9
+Homepage: https://github.com/basho/lager
10
+
11
+
12
+Package: erlang-lager
13
+Architecture: any
14
+Depends: ${shlibs:Depends}, ${misc:Depends}, erlang-base | ${erlang-abi:Depends},
15
+ ${erlang:Depends}, erlang-goldrush
16
+Description: logging framework for Erlang
17
+ Lager (as in the beer) is a logging framework for Erlang. Its purpose is
18
+ to provide a more traditional way to perform logging in an erlang application
19
+ that plays nicely with traditional UNIX logging tools like logrotate and
20
+ syslog.
21
debian.rules
Added
31
1
2
+#!/usr/bin/make -f
3
+# -*- makefile -*-
4
+
5
+# Uncomment this to turn on verbose mode.
6
+#export DH_VERBOSE=1
7
+
8
+include /usr/share/dpkg/pkg-info.mk
9
+
10
+DESTDIR=$(CURDIR)/debian/erlang-lager
11
+
12
+%:
13
+ dh $@ --buildsystem=rebar --with rebar
14
+
15
+override_dh_auto_install:
16
+ dh_auto_install
17
+ for file in include/*.hrl ; do \
18
+ fname=$$(basename $${file}) ; \
19
+ subdir=$$(basename $$(dirname $${file})) ; \
20
+ if [ ! -f $(DESTDIR)/usr/lib/erlang/lib/lager-$(DEB_VERSION_UPSTREAM)/$${subdir}/$${fname} ] ; then \
21
+ install -m 755 -d $(DESTDIR)/usr/lib/erlang/lib/lager-$(DEB_VERSION_UPSTREAM)/$${subdir} ; \
22
+ install -m 644 $${file} \
23
+ $(DESTDIR)/usr/lib/erlang/lib/lager-$(DEB_VERSION_UPSTREAM)/$${subdir} ; \
24
+ fi ; \
25
+ done
26
+
27
+get-orig-source:
28
+ dh_testdir
29
+ wget -O ../erlang-lager_$(DEB_VERSION_UPSTREAM).orig.tar.gz \
30
+ https://github.com/basho/lager/archive/$(DEB_VERSION_UPSTREAM).tar.gz
31
debian.series
Added
debian.tar.gz
Added
erlang-lager.dsc
Added
17
1
2
+Format: 1.0
3
+Source: erlang-lager
4
+Binary: erlang-lager
5
+Architecture: any
6
+Version: 3.1.0-0~kolab1
7
+Maintainer: Philipp Huebner <debalance@debian.org>
8
+Uploaders: Christoph Erhardt <kolab@sicherha.de>
9
+Homepage: https://github.com/basho/lager
10
+Standards-Version: 3.9.5
11
+Build-Depends: debhelper (>= 9), dh-rebar, erlang-goldrush
12
+Package-List:
13
+ erlang-lager deb libs optional
14
+Files:
15
+ 00000000000000000000000000000000 0 lager-3.1.0.tar.gz
16
+ 00000000000000000000000000000000 0 debian.tar.gz
17
lager-2.1.0.tar.gz/README.md -> lager-3.1.0.tar.gz/README.md
Changed
550
1
2
alert, emergency)
3
* Logger calls are transformed using a parse transform to allow capturing
4
Module/Function/Line/Pid information
5
-* When no handler is consuming a log level (eg. debug) no event is even sent
6
+* When no handler is consuming a log level (eg. debug) no event is sent
7
to the log handler
8
* Supports multiple backends, including console and file.
9
+* Supports multiple sinks
10
* Rewrites common OTP error messages into more readable messages
11
* Support for pretty printing records encountered at compile time
12
* Tolerant in the face of large or many log messages, won't out of memory the node
13
+* Optional feature to bypass log size truncation ("unsafe")
14
* Supports internal time and date based rotation, as well as external rotation tools
15
* Syslog style log level comparison flags
16
* Colored terminal output (requires R16+)
17
18
Usage
19
-----
20
To use lager in your application, you need to define it as a rebar dep or have
21
-some other way of including it in erlang's path. You can then add the
22
-following option to the erlang compiler flags
23
+some other way of including it in Erlang's path. You can then add the
24
+following option to the erlang compiler flags:
25
26
```erlang
27
{parse_transform, lager_transform}
28
29
```
30
31
Before logging any messages, you'll need to start the lager application. The
32
-lager module's start function takes care of loading and starting any dependencies
33
+lager module's `start` function takes care of loading and starting any dependencies
34
lager requires.
35
36
```erlang
37
38
lager:warning("Some message with a term: ~p", [Term])
39
```
40
41
-The general form is lager:Severity() where Severity is one of the log levels
42
+The general form is `lager:Severity()` where `Severity` is one of the log levels
43
mentioned above.
44
45
Configuration
46
47
48
```erlang
49
{lager, [
50
+ {log_root, "/var/log/hello"},
51
{handlers, [
52
{lager_console_backend, info},
53
{lager_file_backend, [{file, "error.log"}, {level, error}]},
54
55
]}.
56
```
57
58
+```log_root``` variable is optional, by default file paths are relative to CWD.
59
+
60
The available configuration options for each backend are listed in their
61
module's documentation.
62
63
+Sinks
64
+-----
65
+Lager has traditionally supported a single sink (implemented as a
66
+`gen_event` manager) named `lager_event` to which all backends were
67
+connected.
68
+
69
+Lager now supports extra sinks; each sink can have different
70
+sync/async message thresholds and different backends.
71
+
72
+### Sink configuration
73
+
74
+To use multiple sinks (beyond the built-in sink of lager and lager_event), you
75
+need to:
76
+
77
+1. Setup rebar.config
78
+2. Configure the backends in app.config
79
+
80
+#### Names
81
+
82
+Each sink has two names: one atom to be used like a module name for
83
+sending messages, and that atom with `_lager_event` appended for backend
84
+configuration.
85
+
86
+This reflects the legacy behavior: `lager:info` (or `critical`, or
87
+`debug`, etc) is a way of sending a message to a sink named
88
+`lager_event`. Now developers can invoke `audit:info` or
89
+`myCompanyName:debug` so long as the corresponding `audit_lager_event` or
90
+`myCompanyName_lager_event` sinks are configured.
91
+
92
+#### rebar.config
93
+
94
+In `rebar.config` for the project that requires lager, include a list
95
+of sink names (without the `_lager_event` suffix) in `erl_opts`:
96
+
97
+`{lager_extra_sinks, [audit]}`
98
+
99
+#### Runtime requirements
100
+
101
+To be useful, sinks must be configured at runtime with backends.
102
+
103
+In `app.config` for the project that requires lager, for example,
104
+extend the lager configuration to include an `extra_sinks` tuple with
105
+backends (aka "handlers") and optionally `async_threshold` and
106
+`async_threshold_window` values (see **Overload Protection**
107
+below). If async values are not configured, no overload protection
108
+will be applied on that sink.
109
+
110
+```erlang
111
+[{lager, [
112
+ {log_root, "/tmp"},
113
+
114
+ %% Default handlers for lager/lager_event
115
+ {handlers, [
116
+ {lager_console_backend, info},
117
+ {lager_file_backend, [{file, "error.log"}, {level, error}]},
118
+ {lager_file_backend, [{file, "console.log"}, {level, info}]}
119
+ ]},
120
+
121
+ %% Any other sinks
122
+ {extra_sinks,
123
+ [
124
+ {audit_lager_event,
125
+ [{handlers,
126
+ [{lager_file_backend,
127
+ [{file, "sink1.log"},
128
+ {level, info}
129
+ ]
130
+ }]
131
+ },
132
+ {async_threshold, 500},
133
+ {async_threshold_window, 50}]
134
+ }]
135
+ }
136
+ ]
137
+ }
138
+].
139
+```
140
+
141
Custom Formatting
142
-----------------
143
All loggers have a default formatting that can be overriden. A formatter is any module that
144
-exports format(#lager_log_message{},Config#any()). It is specified as part of the configuration
145
+exports `format(#lager_log_message{},Config#any())`. It is specified as part of the configuration
146
for the backend:
147
148
```erlang
149
150
]}.
151
```
152
153
-Included is lager_default_formatter. This provides a generic, default formatting for log messages using a "semi-iolist"
154
-as configuration. Any iolist allowed elements in the configuration are printed verbatim. Atoms in the configuration
155
-are treated as metadata properties and extracted from the log message.
156
-The metadata properties date,time, message, and severity will always exist.
157
-The properties pid, file, line, module, function, and node will always exist if the parser transform is used.
158
+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":
159
160
-```
161
-["Foo"] -> "Foo", regardless of message content.
162
-[message] -> The content of the logged message, alone.
163
-[{pid,"Unknown Pid"}] -> "<?.?.?>" if pid is in the metadata, "Unknown Pid" if not.
164
-[{pid, ["My pid is ", pid], "Unknown Pid"}] -> if pid is in the metadata print "My pid is <?.?.?>", otherwise print "Unknown Pid"
165
-```
166
+* Any traditional iolist elements in the configuration are printed verbatim.
167
+* Atoms in the configuration are treated as placeholders for lager metadata and extracted from the log message.
168
+ * The placeholders `date`, `time`, `message`, `sev` and `severity` will always exist.
169
+ * `sev` is an abbreviated severity which is interpreted as a capitalized single letter encoding of the severity level
170
+ (e.g. `'debug'` -> `$D`)
171
+ * The placeholders `pid`, `file`, `line`, `module`, `function`, and `node` will always exist if the parse transform is used.
172
+ * Applications can define their own metadata placeholder.
173
+ * A tuple of `{atom(), semi-iolist()}` allows for a fallback for
174
+ the atom placeholder. If the value represented by the atom
175
+ cannot be found, the semi-iolist will be interpreted instead.
176
+ * A tuple of `{atom(), semi-iolist(), semi-iolist()}` represents a
177
+ conditional operator: if a value for the atom placeholder can be
178
+ found, the first semi-iolist will be output; otherwise, the
179
+ second will be used.
180
181
-Optionally, a tuple of {atom(),semi-iolist()}
182
-can be used. The atom will look up the property, but if not found it will use the semi-iolist() instead. These fallbacks
183
-can be nested or refer to other properties.
184
+Examples:
185
186
```
187
+["Foo"] -> "Foo", regardless of message content.
188
+[message] -> The content of the logged message, alone.
189
[{pid,"Unknown Pid"}] -> "<?.?.?>" if pid is in the metadata, "Unknown Pid" if not.
190
-[{server,[$(,{pid,"Unknown Server"},$)]}}] -> user provided server metadata, otherwise "(<?.?.?>)", otherwise "(Unknown Server)"
191
+[{pid, ["My pid is ", pid], ["Unknown Pid"]}] -> if pid is in the metadata print "My pid is <?.?.?>", otherwise print "Unknown Pid"
192
+[{server,{pid, ["(", pid, ")"], ["(Unknown Server)"]}}] -> user provided server metadata, otherwise "(<?.?.?>)", otherwise "(Unknown Server)"
193
```
194
195
Error logger integration
196
------------------------
197
-Lager is also supplied with a error_logger handler module that translates
198
+Lager is also supplied with a `error_logger` handler module that translates
199
traditional erlang error messages into a friendlier format and sends them into
200
lager itself to be treated like a regular lager log call. To disable this, set
201
the lager application variable `error_logger_redirect` to `false`.
202
+You can also disable reformatting for OTP and Cowboy messages by setting variable
203
+`error_logger_format_raw` to `true`.
204
205
-The error_logger handler will also log more complete error messages (protected
206
-with use of trunc_io) to a "crash log" which can be referred to for further
207
+The `error_logger` handler will also log more complete error messages (protected
208
+with use of `trunc_io`) to a "crash log" which can be referred to for further
209
information. The location of the crash log can be specified by the crash_log
210
application variable. If set to `undefined` it is not written at all.
211
212
Messages in the crash log are subject to a maximum message size which can be
213
-specified via the crash_log_msg_size application variable.
214
+specified via the `crash_log_msg_size` application variable.
215
+
216
+Messages from `error_logger` will be redirected to `error_logger_lager_event` sink
217
+if it is defined so it can be redirected to another log file.
218
+For example:
219
220
+```
221
+[{lager, [
222
+ {extra_sinks,
223
+ [
224
+ {error_logger_lager_event,
225
+ [{handlers, [
226
+ {lager_file_backend, [{file, "error_logger.log"}, {level, info}]}]
227
+ }]
228
+ }]
229
+ }]
230
+}].
231
+```
232
+Will send all `error_logger` messages to `error_logger.log` file.
233
Overload Protection
234
-------------------
235
236
-Prior to lager 2.0, the gen_event at the core of lager operated purely in
237
+Prior to lager 2.0, the `gen_event` at the core of lager operated purely in
238
synchronous mode. Asynchronous mode is faster, but has no protection against
239
-message queue overload. In lager 2.0, the gen_event takes a hybrid approach. it
240
+message queue overload. In lager 2.0, the `gen_event` takes a hybrid approach. it
241
polls its own mailbox size and toggles the messaging between synchronous and
242
asynchronous depending on mailbox size.
243
244
245
point synchronous messaging will be used, and switch back to asynchronous, when
246
size reduces to `20 - 5 = 15`.
247
248
-If you wish to disable this behaviour, simply set it to 'undefined'. It defaults
249
+If you wish to disable this behaviour, simply set it to `undefined`. It defaults
250
to a low number to prevent the mailbox growing rapidly beyond the limit and causing
251
problems. In general, lager should process messages as fast as they come in, so getting
252
20 behind should be relatively exceptional anyway.
253
254
-If you want to limit the number of messages per second allowed from error_logger,
255
+If you want to limit the number of messages per second allowed from `error_logger`,
256
which is a good idea if you want to weather a flood of messages when lots of
257
related processes crash, you can set a limit:
258
259
260
261
It is probably best to keep this number small.
262
263
+"Unsafe"
264
+--------
265
+The unsafe code pathway bypasses the normal lager formatting code and uses the
266
+same code as error_logger in OTP. This provides a marginal speedup to your logging
267
+code (we measured between 0.5-1.3% improvement during our benchmarking; others have
268
+reported better improvements.)
269
+
270
+This is a **dangerous** feature. It *will not* protect you against
271
+large log messages - large messages can kill your application and even your
272
+Erlang VM dead due to memory exhaustion as large terms are copied over and
273
+over in a failure cascade. We strongly recommend that this code pathway
274
+only be used by log messages with a well bounded upper size of around 500 bytes.
275
+
276
+If there's any possibility the log messages could exceed that limit, you should
277
+use the normal lager message formatting code which will provide the appropriate
278
+size limitations and protection against memory exhaustion.
279
+
280
+If you want to format an unsafe log message, you may use the severity level (as
281
+usual) followed by `_unsafe`. Here's an example:
282
+
283
+```erlang
284
+lager:info_unsafe("The quick brown ~s jumped over the lazy ~s", ["fox", "dog"]).
285
+```
286
+
287
Runtime loglevel changes
288
------------------------
289
You can change the log level of any lager backend at runtime by doing the
290
291
lager:set_loglevel(lager_file_backend, "console.log", debug).
292
```
293
294
-Lager keeps track of the minium log level being used by any backend and
295
-supresses generation of messages lower than that level. This means that debug
296
+Lager keeps track of the minimum log level being used by any backend and
297
+suppresses generation of messages lower than that level. This means that debug
298
log messages, when no backend is consuming debug messages, are effectively
299
free. A simple benchmark of doing 1 million debug log messages while the
300
minimum threshold was above that takes less than half a second.
301
302
Internal log rotation
303
---------------------
304
Lager can rotate its own logs or have it done via an external process. To
305
-use internal rotation, use the 'size', 'date' and 'count' values in the file
306
+use internal rotation, use the `size`, `date` and `count` values in the file
307
backend's config:
308
309
```erlang
310
-[{name, "error.log"}, {level, error}, {size, 10485760}, {date, "$D0"}, {count, 5}]
311
+[{file, "error.log"}, {level, error}, {size, 10485760}, {date, "$D0"}, {count, 5}]
312
```
313
314
-This tells lager to log error and above messages to "error.log" and to
315
-rotate the file at midnight or when it reaches 10mb, whichever comes first
316
-and to keep 5 rotated logs, in addition to the current one. Setting the
317
+This tells lager to log error and above messages to `error.log` and to
318
+rotate the file at midnight or when it reaches 10mb, whichever comes first,
319
+and to keep 5 rotated logs in addition to the current one. Setting the
320
count to 0 does not disable rotation, it instead rotates the file and keeps
321
no previous versions around. To disable rotation set the size to 0 and the
322
date to "".
323
324
-The "$D0" syntax is taken from the syntax newsyslog uses in newsyslog.conf.
325
+The `$D0` syntax is taken from the syntax newsyslog uses in newsyslog.conf.
326
The relevant extract follows:
327
328
```
329
330
331
To configure the crash log rotation, the following application variables are
332
used:
333
-* crash_log_size
334
-* crash_log_date
335
-* crash_log_count
336
+* `crash_log_size`
337
+* `crash_log_date`
338
+* `crash_log_count`
339
340
-See the .app.src file for further details.
341
+See the `.app.src` file for further details.
342
343
Syslog Support
344
--------------
345
-Lager syslog output is provided as a separate application;
346
+Lager syslog output is provided as a separate application:
347
[lager_syslog](https://github.com/basho/lager_syslog). It is packaged as a
348
-separate application so Lager itself doesn't have an indirect dependancy on a
349
-port driver. Please see the lager_syslog README for configuration information.
350
+separate application so lager itself doesn't have an indirect dependency on a
351
+port driver. Please see the `lager_syslog` README for configuration information.
352
353
Older Backends
354
--------------
355
356
lager available, but they may not have been updated to the new API. As they
357
are updated, links to them can be re-added here.
358
359
+Exception Pretty Printing
360
+----------------------
361
+
362
+```erlang
363
+try
364
+ foo()
365
+catch
366
+ Class:Reason ->
367
+ lager:error(
368
+ "~nStacktrace:~s",
369
+ [lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason})])
370
+end.
371
+```
372
+
373
Record Pretty Printing
374
----------------------
375
Lager's parse transform will keep track of any record definitions it encounters
376
and store them in the module's attributes. You can then, at runtime, print any
377
record a module compiled with the lager parse transform knows about by using the
378
-lager:pr/2 function, which takes the record and the module that knows about the record:
379
+`lager:pr/2` function, which takes the record and the module that knows about the record:
380
381
```erlang
382
lager:info("My state is ~p", [lager:pr(State, ?MODULE)])
383
```
384
385
-Often, ?MODULE is sufficent, but you can obviously substitute that for a literal module name.
386
-lager:pr also works from the shell.
387
+Often, `?MODULE` is sufficent, but you can obviously substitute that for a literal module name.
388
+`lager:pr` also works from the shell.
389
390
Colored terminal output
391
-----------------------
392
-If you have erlang R16 or higher, you can tell lager's console backend to be colored. Simply
393
-add
394
+If you have Erlang R16 or higher, you can tell lager's console backend to be colored. Simply
395
+add to lager's application environment config:
396
397
```erlang
398
{colored, true}
399
```
400
401
-To lager's application environment config. If you don't like the default colors, they are
402
-also configurable, see the app.src file for more details.
403
+If you don't like the default colors, they are also configurable; see
404
+the `.app.src` file for more details.
405
+
406
+The output will be colored from the first occurrence of the atom color
407
+in the formatting configuration. For example:
408
+
409
+```erlang
410
+{lager_console_backend, [info, {lager_default_formatter, [time, color, " [",severity,"] ", message, "\e[0m\r\n"]}]}
411
+```
412
+
413
+This will make the entire log message, except time, colored. The
414
+escape sequence before the line break is needed in order to reset the
415
+color after each log message.
416
417
Tracing
418
-------
419
420
lager:trace_file("logs/example.com.error", [{vhost, "example.com"}], error)
421
```
422
423
-To persist metadata for the life of a process, you can use lager:md/1 to store metadata
424
+To persist metadata for the life of a process, you can use `lager:md/1` to store metadata
425
in the process dictionary:
426
427
```erlang
428
lager:md([{zone, forbidden}])
429
```
430
431
-Note that lager:md will *only* accept a list of key/value pairs keyed by atoms.
432
+Note that `lager:md` will *only* accept a list of key/value pairs keyed by atoms.
433
434
You can also omit the final argument, and the loglevel will default to
435
-'debug'.
436
+`debug`.
437
438
Tracing to the console is similar:
439
440
441
In the above example, the loglevel is omitted, but it can be specified as the
442
second argument if desired.
443
444
-You can also specify multiple expressions in a filter, or use the '*' atom as
445
+You can also specify multiple expressions in a filter, or use the `*` atom as
446
a wildcard to match any message that has that attribute, regardless of its
447
value.
448
449
-Tracing to an existing logfile is also supported, if you wanted to log
450
-warnings from a particular module to the default error.log:
451
+Tracing to an existing logfile is also supported (but see **Multiple
452
+sink support** below):
453
454
```erlang
455
-lager:trace_file("log/error.log", [{module, mymodule}], warning)
456
+lager:trace_file("log/error.log", [{module, mymodule}, {function, myfunction}], warning)
457
```
458
459
-To view the active log backends and traces, you can use the lager:status()
460
-function. To clear all active traces, you can use lager:clear_all_traces().
461
+To view the active log backends and traces, you can use the `lager:status()`
462
+function. To clear all active traces, you can use `lager:clear_all_traces()`.
463
464
To delete a specific trace, store a handle for the trace when you create it,
465
-that you later pass to lager:stop_trace/1:
466
+that you later pass to `lager:stop_trace/1`:
467
468
```erlang
469
{ok, Trace} = lager:trace_file("log/error.log", [{module, mymodule}]),
470
471
element is a comparison operator. The currently supported comparison operators
472
are:
473
474
-* '<' - less than
475
-* '=' - equal to
476
-* '>' - greater than
477
+* `<` - less than
478
+* `=` - equal to
479
+* `>` - greater than
480
481
```erlang
482
lager:trace_console([{request, '>', 117}, {request, '<', 120}])
483
```
484
485
-Using '=' is equivalent to the 2-tuple form.
486
+Using `=` is equivalent to the 2-tuple form.
487
+
488
+### Multiple sink support
489
+
490
+If using multiple sinks, there are limitations on tracing that you
491
+should be aware of.
492
+
493
+Traces are specific to a sink, which can be specified via trace
494
+filters:
495
+
496
+```erlang
497
+lager:trace_file("log/security.log", [{sink, audit}, {function, myfunction}], warning)
498
+```
499
+
500
+If no sink is thus specified, the default lager sink will be used.
501
+
502
+This has two ramifications:
503
+
504
+* Traces cannot intercept messages sent to a different sink.
505
+* Tracing to a file already opened via `lager:trace_file` will only be
506
+ successful if the same sink is specified.
507
+
508
+The former can be ameliorated by opening multiple traces; the latter
509
+can be fixed by rearchitecting lager's file backend, but this has not
510
+been tackled.
511
512
Setting the truncation limit at compile-time
513
--------------------------------------------
514
Lager defaults to truncating messages at 4096 bytes, you can alter this by
515
-using the {lager_truncation_size, X} option. In rebar, you can add it to
516
-erl_opts:
517
+using the `{lager_truncation_size, X}` option. In rebar, you can add it to
518
+`erl_opts`:
519
520
```erlang
521
{erl_opts, [{parse_transform, lager_transform}, {lager_truncation_size, 1024}]}.
522
```
523
524
-You can also pass it to erlc, if you prefer:
525
+You can also pass it to `erlc`, if you prefer:
526
527
```
528
erlc -pa lager/ebin +'{parse_transform, lager_transform}' +'{lager_truncation_size, 1024}' file.erl
529
```
530
+
531
+3.x Changelog
532
+-------------
533
+3.1.0 - 27 January 2016
534
+
535
+ * Feature: API calls to a rotate handler, sink or all. This change
536
+ introduces a new `rotate` message for 3rd party lager backends; that's
537
+ why this is released as a new minor version number. (#311)
538
+
539
+3.0.3 - 27 January 2016
540
+
541
+ * Feature: Pretty printer for human readable stack traces (#298)
542
+ * Feature: Make error reformatting optional (#305)
543
+ * Feature: Optional and explicit sink for error_logger messages (#303)
544
+ * Bugfix: Always explicitly close a file after its been rotated (#316)
545
+ * Bugfix: If a relative path already contains the log root, do not add it again (#317)
546
+ * Bugfix: Configure and start extra sinks before traces are evaluated (#307)
547
+ * Bugfix: Stop and remove traces correctly (#306)
548
+ * Bugfix: A byte value of 255 is valid for Unicode (#300)
549
+ * Dependency: Bump to goldrush 0.1.8 (#313)
550
lager-2.1.0.tar.gz/include/lager.hrl -> lager-3.1.0.tar.gz/include/lager.hrl
Changed
55
1
2
3
-define(DEFAULT_TRUNCATION, 4096).
4
-define(DEFAULT_TRACER, lager_default_tracer).
5
+-define(DEFAULT_SINK, lager_event).
6
+-define(ERROR_LOGGER_SINK, error_logger_lager_event).
7
+
8
9
-define(LEVELS,
10
[debug, info, notice, warning, error, critical, alert, emergency, none]).
11
12
+%% Use of these "functions" means that the argument list will not be
13
+%% truncated for safety
14
+-define(LEVELS_UNSAFE,
15
+ [{debug_unsafe, debug}, {info_unsafe, info}, {notice_unsafe, notice}, {warning_unsafe, warning}, {error_unsafe, error}, {critical_unsafe, critical}, {alert_unsafe, alert}, {emergency_unsafe, emergency}]).
16
+
17
-define(DEBUG, 128).
18
-define(INFO, 64).
19
-define(NOTICE, 32).
20
21
?EMERGENCY -> emergency
22
end).
23
24
+-define(SHOULD_LOG(Sink, Level),
25
+ (lager_util:level_to_num(Level) band element(1, lager_config:get({Sink, loglevel}, {?LOG_NONE, []}))) /= 0).
26
+
27
-define(SHOULD_LOG(Level),
28
(lager_util:level_to_num(Level) band element(1, lager_config:get(loglevel, {?LOG_NONE, []}))) /= 0).
29
30
31
Level,
32
[{pid,Pid},{line,?LINE},{file,?FILE},{module,?MODULE}],
33
[])}
34
- )).
35
+ )).
36
37
%% FOR INTERNAL USE ONLY
38
%% internal non-blocking logging call
39
40
end)).
41
-endif.
42
43
+-record(lager_shaper, {
44
+ %% how many messages per second we try to deliver
45
+ hwm = undefined :: 'undefined' | pos_integer(),
46
+ %% how many messages we've received this second
47
+ mps = 0 :: non_neg_integer(),
48
+ %% the current second
49
+ lasttime = os:timestamp() :: erlang:timestamp(),
50
+ %% count of dropped messages this second
51
+ dropped = 0 :: non_neg_integer()
52
+ }).
53
+
54
+-type lager_shaper() :: #lager_shaper{}.
55
lager-2.1.0.tar.gz/rebar.config -> lager-3.1.0.tar.gz/rebar.config
Changed
57
1
2
-{erl_opts, [debug_info, warn_untyped_record]}.
3
+%% -*- erlang -*-
4
+%% -------------------------------------------------------------------
5
+%%
6
+%% Copyright (c) 2011-2015 Basho Technologies, Inc.
7
+%%
8
+%% This file is provided to you under the Apache License,
9
+%% Version 2.0 (the "License"); you may not use this file
10
+%% except in compliance with the License. You may obtain
11
+%% a copy of the License at
12
+%%
13
+%% http://www.apache.org/licenses/LICENSE-2.0
14
+%%
15
+%% Unless required by applicable law or agreed to in writing,
16
+%% software distributed under the License is distributed on an
17
+%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18
+%% KIND, either express or implied. See the License for the
19
+%% specific language governing permissions and limitations
20
+%% under the License.
21
+%%
22
+%% -------------------------------------------------------------------
23
+
24
+{erl_opts, [
25
+ {lager_extra_sinks, ['__lager_test_sink']},
26
+ debug_info,
27
+ report,
28
+ verbose,
29
+ warn_deprecated_function,
30
+ warn_deprecated_type,
31
+ warn_export_all,
32
+ warn_export_vars,
33
+ warn_obsolete_guard,
34
+ warn_untyped_record,
35
+ warn_unused_import
36
+ % do NOT include warnings_as_errors, as rebar includes these options
37
+ % when compiling for eunit, and at least one test module has code that
38
+ % is deliberatly broken and will generate an un-maskable warning
39
+]}.
40
+
41
{erl_first_files, ["src/lager_util.erl"]}.
42
+
43
+{eunit_opts, [verbose]}.
44
+{eunit_compile_opts, [
45
+ nowarn_untyped_record,
46
+ nowarn_export_all
47
+]}.
48
{deps, [
49
- {goldrush, "0\.1\.6",
50
- {git, "git://github.com/DeadZen/goldrush.git", {tag, "0.1.6"}}}
51
- ]}.
52
+ {goldrush, ".*", {git, "git://github.com/DeadZen/goldrush.git", {tag, "0.1.8"}}}
53
+]}.
54
55
{xref_checks, []}.
56
{xref_queries, [{"(XC - UC) || (XU - X - B - lager_default_tracer : Mod - erlang:\"(is_map|map_size)\"/1 - maps:to_list/1)", []}]}.
57
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
352
1
2
-%% Copyright (c) 2011-2012 Basho Technologies, Inc. All Rights Reserved.
3
+%% Copyright (c) 2011-2015 Basho Technologies, Inc. All Rights Reserved.
4
%%
5
%% This file is provided to you under the Apache License,
6
%% Version 2.0 (the "License"); you may not use this file
7
8
-export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2,
9
code_change/3]).
10
11
--export([format_reason/1]).
12
-
13
--record(state, {
14
- %% how many messages per second we try to deliver
15
- hwm = undefined :: 'undefined' | pos_integer(),
16
- %% how many messages we've received this second
17
- mps = 0 :: non_neg_integer(),
18
- %% the current second
19
- lasttime = os:timestamp() :: erlang:timestamp(),
20
- %% count of dropped messages this second
21
- dropped = 0 :: non_neg_integer()
22
+-export([format_reason/1, format_mfa/1, format_args/3]).
23
+
24
+-record(state, {
25
+ sink :: atom(),
26
+ shaper :: lager_shaper(),
27
+ %% group leader strategy
28
+ groupleader_strategy :: handle | ignore | mirror,
29
+ raw :: boolean()
30
}).
31
32
--define(LOGMSG(Level, Pid, Msg),
33
- case ?SHOULD_LOG(Level) of
34
+-define(LOGMSG(Sink, Level, Pid, Msg),
35
+ case ?SHOULD_LOG(Sink, Level) of
36
true ->
37
- _ =lager:log(Level, Pid, Msg),
38
+ _ =lager:log(Sink, Level, Pid, Msg, []),
39
ok;
40
_ -> ok
41
end).
42
43
--define(LOGFMT(Level, Pid, Fmt, Args),
44
- case ?SHOULD_LOG(Level) of
45
+-define(LOGFMT(Sink, Level, Pid, Fmt, Args),
46
+ case ?SHOULD_LOG(Sink, Level) of
47
true ->
48
- _ = lager:log(Level, Pid, Fmt, Args),
49
+ _ = lager:log(Sink, Level, Pid, Fmt, Args),
50
ok;
51
_ -> ok
52
end).
53
54
gen_event:call(error_logger, ?MODULE, {set_high_water, N}, infinity).
55
56
-spec init(any()) -> {ok, #state{}}.
57
-init([HighWaterMark]) ->
58
- {ok, #state{hwm=HighWaterMark}}.
59
-
60
-handle_call({set_high_water, N}, State) ->
61
- {ok, ok, State#state{hwm = N}};
62
+init([HighWaterMark, GlStrategy]) ->
63
+ Shaper = #lager_shaper{hwm=HighWaterMark},
64
+ Raw = application:get_env(lager, error_logger_format_raw, false),
65
+ Sink = configured_sink(),
66
+ {ok, #state{sink=Sink, shaper=Shaper, groupleader_strategy=GlStrategy, raw=Raw}}.
67
+
68
+handle_call({set_high_water, N}, #state{shaper=Shaper} = State) ->
69
+ NewShaper = Shaper#lager_shaper{hwm=N},
70
+ {ok, ok, State#state{shaper = NewShaper}};
71
handle_call(_Request, State) ->
72
{ok, unknown_call, State}.
73
74
-handle_event(Event, State) ->
75
- case check_hwm(State) of
76
- {true, NewState} ->
77
- log_event(Event, NewState);
78
- {false, NewState} ->
79
- {ok, NewState}
80
+handle_event(Event, #state{sink=Sink, shaper=Shaper} = State) ->
81
+ case lager_util:check_hwm(Shaper) of
82
+ {true, 0, NewShaper} ->
83
+ eval_gl(Event, State#state{shaper=NewShaper});
84
+ {true, Drop, #lager_shaper{hwm=Hwm} = NewShaper} when Drop > 0 ->
85
+ ?LOGFMT(Sink, warning, self(),
86
+ "lager_error_logger_h dropped ~p messages in the last second that exceeded the limit of ~p messages/sec",
87
+ [Drop, Hwm]),
88
+ eval_gl(Event, State#state{shaper=NewShaper});
89
+ {false, _, NewShaper} ->
90
+ {ok, State#state{shaper=NewShaper}}
91
end.
92
93
handle_info(_Info, State) ->
94
95
terminate(_Reason, _State) ->
96
ok.
97
98
+
99
+code_change(_OldVsn, {state, Shaper, GLStrategy}, _Extra) ->
100
+ Raw = application:get_env(lager, error_logger_format_raw, false),
101
+ {ok, #state{
102
+ sink=configured_sink(),
103
+ shaper=Shaper,
104
+ groupleader_strategy=GLStrategy,
105
+ raw=Raw
106
+ }};
107
+code_change(_OldVsn, {state, Sink, Shaper, GLS}, _Extra) ->
108
+ Raw = application:get_env(lager, error_logger_format_raw, false),
109
+ {ok, #state{sink=Sink, shaper=Shaper, groupleader_strategy=GLS, raw=Raw}};
110
code_change(_OldVsn, State, _Extra) ->
111
{ok, State}.
112
113
%% internal functions
114
115
-check_hwm(State = #state{hwm = undefined}) ->
116
- {true, State};
117
-check_hwm(State = #state{mps = Mps, hwm = Hwm}) when Mps < Hwm ->
118
- %% haven't hit high water mark yet, just log it
119
- {true, State#state{mps=Mps+1}};
120
-check_hwm(State = #state{hwm = Hwm, lasttime = Last, dropped = Drop}) ->
121
- %% are we still in the same second?
122
- {M, S, _} = Now = os:timestamp(),
123
- case Last of
124
- {M, S, _} ->
125
- %% still in same second, but have exceeded the high water mark
126
- NewDrops = discard_messages(Now, 0),
127
- {false, State#state{dropped=Drop+NewDrops}};
128
- _ ->
129
- %% different second, reset all counters and allow it
130
- case Drop > 0 of
131
- true ->
132
- ?LOGFMT(warning, self(), "lager_error_logger_h dropped ~p messages in the last second that exceeded the limit of ~p messages/sec",
133
- [Drop, Hwm]);
134
- false ->
135
- ok
136
- end,
137
- {true, State#state{dropped = 0, mps=1, lasttime = Now}}
138
+configured_sink() ->
139
+ case proplists:get_value(?ERROR_LOGGER_SINK, application:get_env(lager, extra_sinks, [])) of
140
+ undefined -> ?DEFAULT_SINK;
141
+ _ -> ?ERROR_LOGGER_SINK
142
end.
143
144
-discard_messages(Second, Count) ->
145
- {M, S, _} = os:timestamp(),
146
- case Second of
147
- {M, S, _} ->
148
- receive
149
- %% we only discard gen_event notifications, because
150
- %% otherwise we might discard gen_event internal
151
- %% messages, such as trapped EXITs
152
- {notify, _Event} ->
153
- discard_messages(Second, Count+1);
154
- {_From, _Tag, {sync_notify, _Event}} ->
155
- discard_messages(Second, Count+1)
156
- after 0 ->
157
- Count
158
- end;
159
- _ ->
160
- Count
161
- end.
162
+eval_gl(Event, #state{groupleader_strategy=GlStrategy0}=State) when is_pid(element(2, Event)) ->
163
+ case element(2, Event) of
164
+ GL when node(GL) =/= node(), GlStrategy0 =:= ignore ->
165
+ gen_event:notify({error_logger, node(GL)}, Event),
166
+ {ok, State};
167
+ GL when node(GL) =/= node(), GlStrategy0 =:= mirror ->
168
+ gen_event:notify({error_logger, node(GL)}, Event),
169
+ log_event(Event, State);
170
+ _ ->
171
+ log_event(Event, State)
172
+ end;
173
+eval_gl(Event, State) ->
174
+ log_event(Event, State).
175
176
-log_event(Event, State) ->
177
+log_event(Event, #state{sink=Sink} = State) ->
178
case Event of
179
{error, _GL, {Pid, Fmt, Args}} ->
180
- case Fmt of
181
- "** Generic server "++_ ->
182
+ FormatRaw = State#state.raw,
183
+ case {FormatRaw, Fmt} of
184
+ {false, "** Generic server "++_} ->
185
%% gen_server terminate
186
[Name, _Msg, _State, Reason] = Args,
187
?CRASH_LOG(Event),
188
- ?LOGFMT(error, Pid, "gen_server ~w terminated with reason: ~s",
189
+ ?LOGFMT(Sink, error, Pid, "gen_server ~w terminated with reason: ~s",
190
[Name, format_reason(Reason)]);
191
- "** State machine "++_ ->
192
+ {false, "** State machine "++_} ->
193
%% gen_fsm terminate
194
[Name, _Msg, StateName, _StateData, Reason] = Args,
195
?CRASH_LOG(Event),
196
- ?LOGFMT(error, Pid, "gen_fsm ~w in state ~w terminated with reason: ~s",
197
+ ?LOGFMT(Sink, error, Pid, "gen_fsm ~w in state ~w terminated with reason: ~s",
198
[Name, StateName, format_reason(Reason)]);
199
- "** gen_event handler"++_ ->
200
+ {false, "** gen_event handler"++_} ->
201
%% gen_event handler terminate
202
[ID, Name, _Msg, _State, Reason] = Args,
203
?CRASH_LOG(Event),
204
- ?LOGFMT(error, Pid, "gen_event ~w installed in ~w terminated with reason: ~s",
205
+ ?LOGFMT(Sink, error, Pid, "gen_event ~w installed in ~w terminated with reason: ~s",
206
[ID, Name, format_reason(Reason)]);
207
- "** Cowboy handler"++_ ->
208
+ {false, "** Cowboy handler"++_} ->
209
%% Cowboy HTTP server error
210
?CRASH_LOG(Event),
211
case Args of
212
[Module, Function, Arity, _Request, _State] ->
213
%% we only get the 5-element list when its a non-exported function
214
- ?LOGFMT(error, Pid,
215
+ ?LOGFMT(Sink, error, Pid,
216
"Cowboy handler ~p terminated with reason: call to undefined function ~p:~p/~p",
217
[Module, Module, Function, Arity]);
218
[Module, Function, Arity, _Class, Reason | Tail] ->
219
%% any other cowboy error_format list *always* ends with the stacktrace
220
StackTrace = lists:last(Tail),
221
- ?LOGFMT(error, Pid,
222
+ ?LOGFMT(Sink, error, Pid,
223
"Cowboy handler ~p terminated in ~p:~p/~p with reason: ~s",
224
[Module, Module, Function, Arity, format_reason({Reason, StackTrace})])
225
end;
226
- "webmachine error"++_ ->
227
+ {false, "Ranch listener "++_} ->
228
+ %% Ranch errors
229
+ ?CRASH_LOG(Event),
230
+ case Args of
231
+ [Ref, _Protocol, Worker, {[{reason, Reason}, {mfa, {Module, Function, Arity}}, {stacktrace, StackTrace} | _], _}] ->
232
+ ?LOGFMT(Sink, error, Worker,
233
+ "Ranch listener ~p terminated in ~p:~p/~p with reason: ~s",
234
+ [Ref, Module, Function, Arity, format_reason({Reason, StackTrace})]);
235
+ [Ref, _Protocol, Worker, Reason] ->
236
+ ?LOGFMT(Sink, error, Worker,
237
+ "Ranch listener ~p terminated with reason: ~s",
238
+ [Ref, format_reason(Reason)])
239
+ end;
240
+ {false, "webmachine error"++_} ->
241
%% Webmachine HTTP server error
242
?CRASH_LOG(Event),
243
[Path, Error] = Args,
244
245
_ ->
246
Error
247
end,
248
- ?LOGFMT(error, Pid, "Webmachine error at path ~p : ~s", [Path, format_reason(StackTrace)]);
249
+ ?LOGFMT(Sink, error, Pid, "Webmachine error at path ~p : ~s", [Path, format_reason(StackTrace)]);
250
_ ->
251
?CRASH_LOG(Event),
252
- ?LOGMSG(error, Pid, lager:safe_format(Fmt, Args, ?DEFAULT_TRUNCATION))
253
+ ?LOGFMT(Sink, error, Pid, Fmt, Args)
254
end;
255
{error_report, _GL, {Pid, std_error, D}} ->
256
?CRASH_LOG(Event),
257
- ?LOGMSG(error, Pid, print_silly_list(D));
258
+ ?LOGMSG(Sink, error, Pid, print_silly_list(D));
259
{error_report, _GL, {Pid, supervisor_report, D}} ->
260
?CRASH_LOG(Event),
261
case lists:sort(D) of
262
[{errorContext, Ctx}, {offender, Off}, {reason, Reason}, {supervisor, Name}] ->
263
Offender = format_offender(Off),
264
- ?LOGFMT(error, Pid,
265
+ ?LOGFMT(Sink, error, Pid,
266
"Supervisor ~w had child ~s exit with reason ~s in context ~w",
267
[supervisor_name(Name), Offender, format_reason(Reason), Ctx]);
268
_ ->
269
- ?LOGMSG(error, Pid, "SUPERVISOR REPORT " ++ print_silly_list(D))
270
+ ?LOGMSG(Sink, error, Pid, "SUPERVISOR REPORT " ++ print_silly_list(D))
271
end;
272
{error_report, _GL, {Pid, crash_report, [Self, Neighbours]}} ->
273
?CRASH_LOG(Event),
274
- ?LOGMSG(error, Pid, "CRASH REPORT " ++ format_crash_report(Self, Neighbours));
275
+ ?LOGMSG(Sink, error, Pid, "CRASH REPORT " ++ format_crash_report(Self, Neighbours));
276
{warning_msg, _GL, {Pid, Fmt, Args}} ->
277
- ?LOGMSG(warning, Pid, lager:safe_format(Fmt, Args, ?DEFAULT_TRUNCATION));
278
+ ?LOGFMT(Sink, warning, Pid, Fmt, Args);
279
{warning_report, _GL, {Pid, std_warning, Report}} ->
280
- ?LOGMSG(warning, Pid, print_silly_list(Report));
281
+ ?LOGMSG(Sink, warning, Pid, print_silly_list(Report));
282
{info_msg, _GL, {Pid, Fmt, Args}} ->
283
- ?LOGMSG(info, Pid, lager:safe_format(Fmt, Args, ?DEFAULT_TRUNCATION));
284
+ ?LOGFMT(Sink, info, Pid, Fmt, Args);
285
{info_report, _GL, {Pid, std_info, D}} when is_list(D) ->
286
Details = lists:sort(D),
287
case Details of
288
[{application, App}, {exited, Reason}, {type, _Type}] ->
289
- ?LOGFMT(info, Pid, "Application ~w exited with reason: ~s",
290
- [App, format_reason(Reason)]);
291
+ case application:get_env(lager, suppress_application_start_stop) of
292
+ {ok, true} when Reason == stopped ->
293
+ ok;
294
+ _ ->
295
+ ?LOGFMT(Sink, info, Pid, "Application ~w exited with reason: ~s",
296
+ [App, format_reason(Reason)])
297
+ end;
298
_ ->
299
- ?LOGMSG(info, Pid, print_silly_list(D))
300
+ ?LOGMSG(Sink, info, Pid, print_silly_list(D))
301
end;
302
{info_report, _GL, {Pid, std_info, D}} ->
303
- ?LOGFMT(info, Pid, "~w", [D]);
304
+ ?LOGFMT(Sink, info, Pid, "~w", [D]);
305
{info_report, _GL, {P, progress, D}} ->
306
Details = lists:sort(D),
307
case Details of
308
[{application, App}, {started_at, Node}] ->
309
- ?LOGFMT(info, P, "Application ~w started on node ~w",
310
- [App, Node]);
311
+ case application:get_env(lager, suppress_application_start_stop) of
312
+ {ok, true} ->
313
+ ok;
314
+ _ ->
315
+ ?LOGFMT(Sink, info, P, "Application ~w started on node ~w",
316
+ [App, Node])
317
+ end;
318
[{started, Started}, {supervisor, Name}] ->
319
MFA = format_mfa(get_value(mfargs, Started)),
320
Pid = get_value(pid, Started),
321
- ?LOGFMT(debug, P, "Supervisor ~w started ~s at pid ~w",
322
+ ?LOGFMT(Sink, debug, P, "Supervisor ~w started ~s at pid ~w",
323
[supervisor_name(Name), MFA, Pid]);
324
_ ->
325
- ?LOGMSG(info, P, "PROGRESS REPORT " ++ print_silly_list(D))
326
+ ?LOGMSG(Sink, info, P, "PROGRESS REPORT " ++ print_silly_list(D))
327
end;
328
_ ->
329
- ?LOGFMT(warning, self(), "Unexpected error_logger event ~w", [Event])
330
+ ?LOGFMT(Sink, warning, self(), "Unexpected error_logger event ~w", [Event])
331
end,
332
{ok, State}.
333
334
335
format_reason({if_clause, [MFA|_]}) ->
336
["no true branch found while evaluating if expression in ", format_mfa(MFA)];
337
format_reason({{try_clause, Val}, [MFA|_]}) ->
338
- ["no try clause matching ", print_val(Val), " in ", format_mfa(MFA)];
339
+ ["no try clause matching ", print_val(Val), " in ", format_mfa(MFA)];
340
format_reason({badarith, [MFA|_]}) ->
341
["bad arithmetic expression in ", format_mfa(MFA)];
342
format_reason({{badmatch, Val}, [MFA|_]}) ->
343
344
%% seems to be generated by a bad call to a BIF
345
["bad argument in ", format_mfa(MFA)]
346
end;
347
+format_reason({{badarg, Stack}, _}) ->
348
+ format_reason({badarg, Stack});
349
format_reason({{badarity, {Fun, Args}}, [MFA|_]}) ->
350
{arity, Arity} = lists:keyfind(arity, 1, erlang:fun_info(Fun)),
351
[io_lib:format("fun called with wrong arity of ~w instead of ~w in ",
352
lager-2.1.0.tar.gz/src/lager.app.src -> lager-3.1.0.tar.gz/src/lager.app.src
Changed
45
1
2
{application, lager,
3
[
4
{description, "Erlang logging framework"},
5
- {vsn, "2.1.0"},
6
+ {vsn, "3.1.0"},
7
{modules, []},
8
{applications, [
9
kernel,
10
11
{registered, [lager_sup, lager_event, lager_crash_log, lager_handler_watcher_sup]},
12
{mod, {lager_app, []}},
13
{env, [
14
- %% Note: application:start(lager) overwrites previously defined environment variables
15
+ %% Note: application:start(lager) overwrites previously defined environment variables
16
%% thus declaration of default handlers is done at lager_app.erl
17
-
18
+
19
%% What colors to use with what log levels
20
{colored, false},
21
{colors, [
22
23
%% Number of rotated crash logs to keep, 0 means keep only the
24
%% current one - default is 0
25
{crash_log_count, 5},
26
- %% Whether to redirect error_logger messages into lager - defaults to true
27
+ %% Whether to redirect error_logger messages into the default lager_event sink - defaults to true
28
{error_logger_redirect, true},
29
%% How many messages per second to allow from error_logger before we start dropping them
30
{error_logger_hwm, 50},
31
- %% How big the gen_event mailbox can get before it is switched into sync mode
32
+ %% How big the gen_event mailbox can get before it is
33
+ %% switched into sync mode. This value only applies to
34
+ %% the default sink; extra sinks can supply their own.
35
{async_threshold, 20},
36
- %% Switch back to async mode, when gen_event mailbox size decrease from `async_threshold'
37
- %% to async_threshold - async_threshold_window
38
+ %% Switch back to async mode, when gen_event mailbox size
39
+ %% decrease from `async_threshold' to async_threshold -
40
+ %% async_threshold_window. This value only applies to the
41
+ %% default sink; extra sinks can supply their own.
42
{async_threshold_window, 5}
43
]}
44
]}.
45
lager-2.1.0.tar.gz/src/lager.erl -> lager-3.1.0.tar.gz/src/lager.erl
Changed
621
1
2
-include("lager.hrl").
3
4
-define(LAGER_MD_KEY, '__lager_metadata').
5
+-define(TRACE_SINK, '__trace_sink').
6
+-define(ROTATE_TIMEOUT, 100000).
7
8
%% API
9
-export([start/0,
10
- log/3, log/4,
11
+ log/3, log/4, log/5,
12
+ log_unsafe/4,
13
md/0, md/1,
14
+ rotate_handler/1, rotate_handler/2, rotate_sink/1, rotate_all/0,
15
trace/2, trace/3, trace_file/2, trace_file/3, trace_file/4, trace_console/1, trace_console/2,
16
- clear_all_traces/0, stop_trace/1, status/0,
17
- get_loglevel/1, set_loglevel/2, set_loglevel/3, get_loglevels/0,
18
- update_loglevel_config/0, posix_error/1,
19
- safe_format/3, safe_format_chop/3, dispatch_log/5, dispatch_log/9,
20
- do_log/9, pr/2]).
21
+ list_all_sinks/0, clear_all_traces/0, stop_trace/1, stop_trace/3, status/0,
22
+ get_loglevel/1, get_loglevel/2, set_loglevel/2, set_loglevel/3, set_loglevel/4, get_loglevels/1,
23
+ update_loglevel_config/1, posix_error/1, set_loghwm/2, set_loghwm/3, set_loghwm/4,
24
+ safe_format/3, safe_format_chop/3, unsafe_format/2, dispatch_log/5, dispatch_log/7, dispatch_log/9,
25
+ do_log/9, do_log/10, do_log_unsafe/10, pr/2, pr/3, pr_stacktrace/1, pr_stacktrace/2]).
26
27
-type log_level() :: debug | info | notice | warning | error | critical | alert | emergency.
28
-type log_level_number() :: 0..7.
29
30
md(_) ->
31
erlang:error(badarg).
32
33
--spec dispatch_log(log_level(), list(), string(), list() | none, pos_integer()) -> ok | {error, lager_not_running}.
34
+
35
+-spec dispatch_log(atom(), log_level(), list(), string(), list() | none, pos_integer(), safe | unsafe) -> ok | {error, lager_not_running} | {error, {sink_not_configured, atom()}}.
36
%% this is the same check that the parse transform bakes into the module at compile time
37
-dispatch_log(Severity, Metadata, Format, Args, Size) when is_atom(Severity)->
38
+%% see lager_transform (lines 173-216)
39
+dispatch_log(Sink, Severity, Metadata, Format, Args, Size, Safety) when is_atom(Severity)->
40
SeverityAsInt=lager_util:level_to_num(Severity),
41
- case {whereis(lager_event), lager_config:get(loglevel, {?LOG_NONE, []})} of
42
- {undefined, _} ->
43
- {error, lager_not_running};
44
- {Pid, {Level, Traces}} when (Level band SeverityAsInt) /= 0 orelse Traces /= [] ->
45
- do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, Level, Traces, Pid);
46
- _ ->
47
- ok
48
+ case {whereis(Sink), whereis(?DEFAULT_SINK), lager_config:get({Sink, loglevel}, {?LOG_NONE, []})} of
49
+ {undefined, undefined, _} -> {error, lager_not_running};
50
+ {undefined, _LagerEventPid0, _} -> {error, {sink_not_configured, Sink}};
51
+ {SinkPid, _LagerEventPid1, {Level, Traces}} when Safety =:= safe andalso ( (Level band SeverityAsInt) /= 0 orelse Traces /= [] ) ->
52
+ do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, Level, Traces, Sink, SinkPid);
53
+ {SinkPid, _LagerEventPid1, {Level, Traces}} when Safety =:= unsafe andalso ( (Level band SeverityAsInt) /= 0 orelse Traces /= [] ) ->
54
+ do_log_unsafe(Severity, Metadata, Format, Args, Size, SeverityAsInt, Level, Traces, Sink, SinkPid);
55
+ _ -> ok
56
end.
57
58
%% @private Should only be called externally from code generated from the parse transform
59
-do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, LevelThreshold, TraceFilters, Pid) when is_atom(Severity) ->
60
- Destinations = case TraceFilters of
61
+do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid) when is_atom(Severity) ->
62
+ FormatFun = fun() -> safe_format_chop(Format, Args, Size) end,
63
+ do_log_impl(Severity, Metadata, Format, Args, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid, FormatFun).
64
+
65
+do_log_impl(Severity, Metadata, Format, Args, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid, FormatFun) ->
66
+ {Destinations, TraceSinkPid} = case TraceFilters of
67
[] ->
68
- [];
69
+ {[], undefined};
70
_ ->
71
- lager_util:check_traces(Metadata,SeverityAsInt,TraceFilters,[])
72
+ {lager_util:check_traces(Metadata,SeverityAsInt,TraceFilters,[]), whereis(?TRACE_SINK)}
73
end,
74
case (LevelThreshold band SeverityAsInt) /= 0 orelse Destinations /= [] of
75
true ->
76
Msg = case Args of
77
A when is_list(A) ->
78
- safe_format_chop(Format,Args,Size);
79
+ FormatFun();
80
_ ->
81
Format
82
end,
83
LagerMsg = lager_msg:new(Msg,
84
Severity, Metadata, Destinations),
85
- case lager_config:get(async, false) of
86
+ case lager_config:get({Sink, async}, false) of
87
true ->
88
- gen_event:notify(Pid, {log, LagerMsg});
89
+ gen_event:notify(SinkPid, {log, LagerMsg});
90
false ->
91
- gen_event:sync_notify(Pid, {log, LagerMsg})
92
+ gen_event:sync_notify(SinkPid, {log, LagerMsg})
93
+ end,
94
+ case TraceSinkPid /= undefined of
95
+ true ->
96
+ gen_event:notify(TraceSinkPid, {log, LagerMsg});
97
+ false ->
98
+ ok
99
end;
100
false ->
101
ok
102
end.
103
104
+%% @private Should only be called externally from code generated from the parse transform
105
+%% Specifically, it would be level ++ `_unsafe' as in `info_unsafe'.
106
+do_log_unsafe(Severity, Metadata, Format, Args, _Size, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid) when is_atom(Severity) ->
107
+ FormatFun = fun() -> unsafe_format(Format, Args) end,
108
+ do_log_impl(Severity, Metadata, Format, Args, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid, FormatFun).
109
+
110
+
111
%% backwards compatible with beams compiled with lager 1.x
112
dispatch_log(Severity, _Module, _Function, _Line, _Pid, Metadata, Format, Args, Size) ->
113
dispatch_log(Severity, Metadata, Format, Args, Size).
114
115
+%% backwards compatible with beams compiled with lager 2.x
116
+dispatch_log(Severity, Metadata, Format, Args, Size) ->
117
+ dispatch_log(?DEFAULT_SINK, Severity, Metadata, Format, Args, Size, safe).
118
+
119
+%% backwards compatible with beams compiled with lager 2.x
120
+do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, LevelThreshold, TraceFilters, SinkPid) ->
121
+ do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt,
122
+ LevelThreshold, TraceFilters, ?DEFAULT_SINK, SinkPid).
123
+
124
+
125
+%% TODO:
126
+%% Consider making log2/4 that takes the Level, Pid and Message params of log/3
127
+%% along with a Sink param??
128
+
129
%% @doc Manually log a message into lager without using the parse transform.
130
-spec log(log_level(), pid() | atom() | [tuple(),...], list()) -> ok | {error, lager_not_running}.
131
log(Level, Pid, Message) when is_pid(Pid); is_atom(Pid) ->
132
133
log(Level, Metadata, Format, Args) when is_list(Metadata) ->
134
dispatch_log(Level, Metadata, Format, Args, ?DEFAULT_TRUNCATION).
135
136
+log_unsafe(Level, Metadata, Format, Args) when is_list(Metadata) ->
137
+ dispatch_log(?DEFAULT_SINK, Level, Metadata, Format, Args, ?DEFAULT_TRUNCATION, unsafe).
138
+
139
+
140
+%% @doc Manually log a message into lager without using the parse transform.
141
+-spec log(atom(), log_level(), pid() | atom() | [tuple(),...], string(), list()) -> ok | {error, lager_not_running}.
142
+log(Sink, Level, Pid, Format, Args) when is_pid(Pid); is_atom(Pid) ->
143
+ dispatch_log(Sink, Level, [{pid,Pid}], Format, Args, ?DEFAULT_TRUNCATION, safe);
144
+log(Sink, Level, Metadata, Format, Args) when is_list(Metadata) ->
145
+ dispatch_log(Sink, Level, Metadata, Format, Args, ?DEFAULT_TRUNCATION, safe).
146
+
147
+validate_trace_filters(Filters, Level, Backend) ->
148
+ Sink = proplists:get_value(sink, Filters, ?DEFAULT_SINK),
149
+ {Sink,
150
+ lager_util:validate_trace({
151
+ proplists:delete(sink, Filters),
152
+ Level,
153
+ Backend
154
+ })
155
+ }.
156
+
157
trace_file(File, Filter) ->
158
trace_file(File, Filter, debug, []).
159
160
161
162
trace_file(File, Filter, Options) when is_list(Options) ->
163
trace_file(File, Filter, debug, Options).
164
-
165
+
166
trace_file(File, Filter, Level, Options) ->
167
- Trace0 = {Filter, Level, {lager_file_backend, File}},
168
- case lager_util:validate_trace(Trace0) of
169
- {ok, Trace} ->
170
- Handlers = gen_event:which_handlers(lager_event),
171
+ FileName = lager_util:expand_path(File),
172
+ case validate_trace_filters(Filter, Level, {lager_file_backend, FileName}) of
173
+ {Sink, {ok, Trace}} ->
174
+ Handlers = lager_config:global_get(handlers, []),
175
%% check if this file backend is already installed
176
- Res = case lists:member({lager_file_backend, File}, Handlers) of
177
- false ->
178
- %% install the handler
179
- LogFileConfig = lists:keystore(level, 1, lists:keystore(file, 1, Options, {file, File}), {level, none}),
180
- supervisor:start_child(lager_handler_watcher_sup,
181
- [lager_event, {lager_file_backend, File}, LogFileConfig]);
182
- _ ->
183
- {ok, exists}
184
+ Res = case lists:keyfind({lager_file_backend, FileName}, 1, Handlers) of
185
+ false ->
186
+ %% install the handler
187
+ LogFileConfig =
188
+ lists:keystore(level, 1,
189
+ lists:keystore(file, 1,
190
+ Options,
191
+ {file, FileName}),
192
+ {level, none}),
193
+ HandlerInfo =
194
+ lager_app:start_handler(Sink, {lager_file_backend, FileName},
195
+ LogFileConfig),
196
+ lager_config:global_set(handlers, [HandlerInfo|Handlers]),
197
+ {ok, installed};
198
+ {_Watcher, _Handler, Sink} ->
199
+ {ok, exists};
200
+ {_Watcher, _Handler, _OtherSink} ->
201
+ {error, file_in_use}
202
end,
203
case Res of
204
{ok, _} ->
205
- add_trace_to_loglevel_config(Trace),
206
- {ok, Trace};
207
+ add_trace_to_loglevel_config(Trace, Sink),
208
+ {ok, {{lager_file_backend, FileName}, Filter, Level}};
209
{error, _} = E ->
210
E
211
end;
212
- Error ->
213
+ {_Sink, Error} ->
214
Error
215
end.
216
217
-
218
trace_console(Filter) ->
219
trace_console(Filter, debug).
220
221
222
trace(Backend, Filter) ->
223
trace(Backend, Filter, debug).
224
225
+trace({lager_file_backend, File}, Filter, Level) ->
226
+ trace_file(File, Filter, Level);
227
+
228
trace(Backend, Filter, Level) ->
229
- Trace0 = {Filter, Level, Backend},
230
- case lager_util:validate_trace(Trace0) of
231
- {ok, Trace} ->
232
- add_trace_to_loglevel_config(Trace),
233
- {ok, Trace};
234
- Error ->
235
+ case validate_trace_filters(Filter, Level, Backend) of
236
+ {Sink, {ok, Trace}} ->
237
+ add_trace_to_loglevel_config(Trace, Sink),
238
+ {ok, {Backend, Filter, Level}};
239
+ {_Sink, Error} ->
240
+ Error
241
+ end.
242
+
243
+stop_trace(Backend, Filter, Level) ->
244
+ case validate_trace_filters(Filter, Level, Backend) of
245
+ {Sink, {ok, Trace}} ->
246
+ stop_trace_int(Trace, Sink);
247
+ {_Sink, Error} ->
248
Error
249
end.
250
251
-stop_trace({_Filter, _Level, Target} = Trace) ->
252
- {Level, Traces} = lager_config:get(loglevel),
253
+stop_trace({Backend, Filter, Level}) ->
254
+ stop_trace(Backend, Filter, Level).
255
+
256
+%% Important: validate_trace_filters orders the arguments of
257
+%% trace tuples differently than the way outside callers have
258
+%% the trace tuple.
259
+%%
260
+%% That is to say, outside they are represented as
261
+%% `{Backend, Filter, Level}'
262
+%%
263
+%% and when they come back from validation, they're
264
+%% `{Filter, Level, Backend}'
265
+stop_trace_int({_Filter, _Level, Backend} = Trace, Sink) ->
266
+ {Level, Traces} = lager_config:get({Sink, loglevel}),
267
NewTraces = lists:delete(Trace, Traces),
268
_ = lager_util:trace_filter([ element(1, T) || T <- NewTraces ]),
269
%MinLevel = minimum_loglevel(get_loglevels() ++ get_trace_levels(NewTraces)),
270
- lager_config:set(loglevel, {Level, NewTraces}),
271
- case get_loglevel(Target) of
272
+ lager_config:set({Sink, loglevel}, {Level, NewTraces}),
273
+ case get_loglevel(Sink, Backend) of
274
none ->
275
%% check no other traces point here
276
- case lists:keyfind(Target, 3, NewTraces) of
277
+ case lists:keyfind(Backend, 3, NewTraces) of
278
false ->
279
- gen_event:delete_handler(lager_event, Target, []);
280
+ gen_event:delete_handler(Sink, Backend, []),
281
+ lager_config:global_set(handlers,
282
+ lists:keydelete(Backend, 1,
283
+ lager_config:global_get(handlers)));
284
_ ->
285
ok
286
end;
287
288
end,
289
ok.
290
291
+list_all_sinks() ->
292
+ sets:to_list(
293
+ lists:foldl(fun({_Watcher, _Handler, Sink}, Set) ->
294
+ sets:add_element(Sink, Set)
295
+ end,
296
+ sets:new(),
297
+ lager_config:global_get(handlers, []))).
298
+
299
+clear_traces_by_sink(Sinks) ->
300
+ lists:foreach(fun(S) ->
301
+ {Level, _Traces} =
302
+ lager_config:get({S, loglevel}),
303
+ lager_config:set({S, loglevel},
304
+ {Level, []})
305
+ end,
306
+ Sinks).
307
+
308
clear_all_traces() ->
309
- {Level, _Traces} = lager_config:get(loglevel),
310
+ Handlers = lager_config:global_get(handlers, []),
311
+ clear_traces_by_sink(list_all_sinks()),
312
_ = lager_util:trace_filter(none),
313
- lager_config:set(loglevel, {Level, []}),
314
- lists:foreach(fun(Handler) ->
315
- case get_loglevel(Handler) of
316
- none ->
317
- gen_event:delete_handler(lager_event, Handler, []);
318
- _ ->
319
- ok
320
- end
321
- end, gen_event:which_handlers(lager_event)).
322
+ lager_config:global_set(handlers,
323
+ lists:filter(
324
+ fun({Handler, _Watcher, Sink}) ->
325
+ case get_loglevel(Sink, Handler) of
326
+ none ->
327
+ gen_event:delete_handler(Sink, Handler, []),
328
+ false;
329
+ _ ->
330
+ true
331
+ end
332
+ end, Handlers)).
333
+
334
+find_traces(Sinks) ->
335
+ lists:foldl(fun(S, Acc) ->
336
+ {_Level, Traces} = lager_config:get({S, loglevel}),
337
+ Acc ++ lists:map(fun(T) -> {S, T} end, Traces)
338
+ end,
339
+ [],
340
+ Sinks).
341
342
status() ->
343
- Handlers = gen_event:which_handlers(lager_event),
344
- TraceCount = case length(element(2, lager_config:get(loglevel))) of
345
+ Handlers = lager_config:global_get(handlers, []),
346
+ Sinks = lists:sort(list_all_sinks()),
347
+ Traces = find_traces(Sinks),
348
+ TraceCount = case length(Traces) of
349
0 -> 1;
350
N -> N
351
end,
352
Status = ["Lager status:\n",
353
[begin
354
- Level = get_loglevel(Handler),
355
+ Level = get_loglevel(Sink, Handler),
356
case Handler of
357
{lager_file_backend, File} ->
358
- io_lib:format("File ~s at level ~p\n", [File, Level]);
359
+ io_lib:format("File ~s (~s) at level ~p\n", [File, Sink, Level]);
360
lager_console_backend ->
361
- io_lib:format("Console at level ~p\n", [Level]);
362
+ io_lib:format("Console (~s) at level ~p\n", [Sink, Level]);
363
_ ->
364
[]
365
end
366
- end || Handler <- Handlers],
367
+ end || {Handler, _Watcher, Sink} <- lists:sort(fun({_, _, S1},
368
+ {_, _, S2}) -> S1 =< S2 end,
369
+ Handlers)],
370
"Active Traces:\n",
371
[begin
372
LevelName = case Level of
373
374
Num ->
375
lager_util:num_to_level(Num)
376
end,
377
- io_lib:format("Tracing messages matching ~p at level ~p to ~p\n",
378
- [Filter, LevelName, Destination])
379
- end || {Filter, Level, Destination} <- element(2, lager_config:get(loglevel))],
380
+ io_lib:format("Tracing messages matching ~p (sink ~s) at level ~p to ~p\n",
381
+ [Filter, Sink, LevelName, Destination])
382
+ end || {Sink, {Filter, Level, Destination}} <- Traces],
383
[
384
"Tracing Reductions:\n",
385
case ?DEFAULT_TRACER:info('query') of
386
387
],
388
[
389
"Tracing Statistics:\n ",
390
- [ begin
391
+ [ begin
392
[" ", atom_to_list(Table), ": ",
393
integer_to_list(?DEFAULT_TRACER:info(Table) div TraceCount),
394
"\n"]
395
396
397
%% @doc Set the loglevel for a particular backend.
398
set_loglevel(Handler, Level) when is_atom(Level) ->
399
- Reply = gen_event:call(lager_event, Handler, {set_loglevel, Level}, infinity),
400
- update_loglevel_config(),
401
- Reply.
402
+ set_loglevel(?DEFAULT_SINK, Handler, undefined, Level).
403
404
%% @doc Set the loglevel for a particular backend that has multiple identifiers
405
%% (eg. the file backend).
406
set_loglevel(Handler, Ident, Level) when is_atom(Level) ->
407
- Reply = gen_event:call(lager_event, {Handler, Ident}, {set_loglevel, Level}, infinity),
408
- update_loglevel_config(),
409
+ set_loglevel(?DEFAULT_SINK, Handler, Ident, Level).
410
+
411
+%% @doc Set the loglevel for a particular sink's backend that potentially has
412
+%% multiple identifiers. (Use `undefined' if it doesn't have any.)
413
+set_loglevel(Sink, Handler, Ident, Level) when is_atom(Level) ->
414
+ HandlerArg = case Ident of
415
+ undefined -> Handler;
416
+ _ -> {Handler, Ident}
417
+ end,
418
+ Reply = gen_event:call(Sink, HandlerArg, {set_loglevel, Level}, infinity),
419
+ update_loglevel_config(Sink),
420
Reply.
421
422
-%% @doc Get the loglevel for a particular backend. In the case that the backend
423
-%% has multiple identifiers, the lowest is returned
424
+
425
+%% @doc Get the loglevel for a particular backend on the default sink. In the case that the backend
426
+%% has multiple identifiers, the lowest is returned.
427
get_loglevel(Handler) ->
428
- case gen_event:call(lager_event, Handler, get_loglevel, infinity) of
429
+ get_loglevel(?DEFAULT_SINK, Handler).
430
+
431
+%% @doc Get the loglevel for a particular sink's backend. In the case that the backend
432
+%% has multiple identifiers, the lowest is returned.
433
+get_loglevel(Sink, Handler) ->
434
+ case gen_event:call(Sink, Handler, get_loglevel, infinity) of
435
{mask, Mask} ->
436
case lager_util:mask_to_levels(Mask) of
437
[] -> none;
438
439
safe_format_chop("~p", [Error], ?DEFAULT_TRUNCATION).
440
441
%% @private
442
-get_loglevels() ->
443
- [gen_event:call(lager_event, Handler, get_loglevel, infinity) ||
444
- Handler <- gen_event:which_handlers(lager_event)].
445
+get_loglevels(Sink) ->
446
+ [gen_event:call(Sink, Handler, get_loglevel, infinity) ||
447
+ Handler <- gen_event:which_handlers(Sink)].
448
+
449
+%% @doc Set the loghwm for the default sink.
450
+set_loghwm(Handler, Hwm) when is_integer(Hwm) ->
451
+ set_loghwm(?DEFAULT_SINK, Handler, Hwm).
452
+
453
+%% @doc Set the loghwm for a particular backend.
454
+set_loghwm(Sink, Handler, Hwm) when is_integer(Hwm) ->
455
+ gen_event:call(Sink, Handler, {set_loghwm, Hwm}, infinity).
456
+
457
+%% @doc Set the loghwm (log high water mark) for file backends with multiple identifiers
458
+set_loghwm(Sink, Handler, Ident, Hwm) when is_integer(Hwm) ->
459
+ gen_event:call(Sink, {Handler, Ident}, {set_loghwm, Hwm}, infinity).
460
461
%% @private
462
-add_trace_to_loglevel_config(Trace) ->
463
- {MinLevel, Traces} = lager_config:get(loglevel),
464
+add_trace_to_loglevel_config(Trace, Sink) ->
465
+ {MinLevel, Traces} = lager_config:get({Sink, loglevel}),
466
case lists:member(Trace, Traces) of
467
false ->
468
NewTraces = [Trace|Traces],
469
_ = lager_util:trace_filter([ element(1, T) || T <- NewTraces]),
470
- lager_config:set(loglevel, {MinLevel, [Trace|Traces]});
471
+ lager_config:set({Sink, loglevel}, {MinLevel, [Trace|Traces]});
472
_ ->
473
ok
474
end.
475
476
%% @doc recalculate min log level
477
-update_loglevel_config() ->
478
- {_, Traces} = lager_config:get(loglevel),
479
- MinLog = minimum_loglevel(get_loglevels()),
480
- lager_config:set(loglevel, {MinLog, Traces}).
481
+update_loglevel_config(error_logger) ->
482
+ %% Not a sink under our control, part of the Erlang logging
483
+ %% utility that error_logger_lager_h attaches to
484
+ true;
485
+update_loglevel_config(Sink) ->
486
+ {_, Traces} = lager_config:get({Sink, loglevel}, {ignore_me, []}),
487
+ MinLog = minimum_loglevel(get_loglevels(Sink)),
488
+ lager_config:set({Sink, loglevel}, {MinLog, Traces}).
489
490
%% @private
491
minimum_loglevel(Levels) ->
492
493
safe_format_chop(Fmt, Args, Limit) ->
494
safe_format(Fmt, Args, Limit, [{chomp, true}]).
495
496
+%% @private Print the format string `Fmt' with `Args' without a size limit.
497
+%% This is unsafe because the output of this function is unbounded.
498
+%%
499
+%% Log messages with unbounded size will kill your application dead as
500
+%% OTP mechanisms stuggle to cope with them. So this function is
501
+%% intended <b>only</b> for messages which have a reasonable bounded
502
+%% size before they're formatted.
503
+%%
504
+%% If the format string is invalid or not enough arguments are
505
+%% supplied a 'FORMAT ERROR' message is printed instead with the
506
+%% offending arguments. The caller is NOT crashed.
507
+unsafe_format(Fmt, Args) ->
508
+ try io_lib:format(Fmt, Args)
509
+ catch
510
+ _:_ -> io_lib:format("FORMAT ERROR: ~p ~p", [Fmt, Args])
511
+ end.
512
+
513
%% @doc Print a record lager found during parse transform
514
pr(Record, Module) when is_tuple(Record), is_atom(element(1, Record)) ->
515
+ pr(Record, Module, []);
516
+pr(Record, _) ->
517
+ Record.
518
+
519
+%% @doc Print a record lager found during parse transform
520
+pr(Record, Module, Options) when is_tuple(Record), is_atom(element(1, Record)), is_list(Options) ->
521
try
522
case is_record_known(Record, Module) of
523
false ->
524
Record;
525
{RecordName, RecordFields} ->
526
{'$lager_record', RecordName,
527
- zip(RecordFields, tl(tuple_to_list(Record)), Module, [])}
528
+ zip(RecordFields, tl(tuple_to_list(Record)), Module, Options, [])}
529
end
530
catch
531
error:undef ->
532
Record
533
end;
534
-pr(Record, _) ->
535
+pr(Record, _, _) ->
536
Record.
537
538
-zip([FieldName|RecordFields], [FieldValue|Record], Module, ToReturn) ->
539
+zip([FieldName|RecordFields], [FieldValue|Record], Module, Options, ToReturn) ->
540
+ Compress = lists:member(compress, Options),
541
case is_tuple(FieldValue) andalso
542
tuple_size(FieldValue) > 0 andalso
543
is_atom(element(1, FieldValue)) andalso
544
is_record_known(FieldValue, Module) of
545
+ false when Compress andalso FieldValue =:= undefined ->
546
+ zip(RecordFields, Record, Module, Options, ToReturn);
547
false ->
548
- zip(RecordFields, Record, Module, [{FieldName, FieldValue}|ToReturn]);
549
+ zip(RecordFields, Record, Module, Options, [{FieldName, FieldValue}|ToReturn]);
550
_Else ->
551
- F = {FieldName, pr(FieldValue, Module)},
552
- zip(RecordFields, Record, Module, [F|ToReturn])
553
+ F = {FieldName, pr(FieldValue, Module, Options)},
554
+ zip(RecordFields, Record, Module, Options, [F|ToReturn])
555
end;
556
-zip([], [], _Module, ToReturn) ->
557
+zip([], [], _Module, _Compress, ToReturn) ->
558
lists:reverse(ToReturn).
559
560
-is_record_known(Record, Module) ->
561
+is_record_known(Record, Module) ->
562
Name = element(1, Record),
563
Attrs = Module:module_info(attributes),
564
case lists:keyfind(lager_records, 1, Attrs) of
565
false -> false;
566
- {lager_records, Records} ->
567
+ {lager_records, Records} ->
568
case lists:keyfind(Name, 1, Records) of
569
false -> false;
570
- {Name, RecordFields} ->
571
+ {Name, RecordFields} ->
572
case (tuple_size(Record) - 1) =:= length(RecordFields) of
573
false -> false;
574
true -> {Name, RecordFields}
575
end
576
end
577
end.
578
+
579
+
580
+%% @doc Print stacktrace in human readable form
581
+pr_stacktrace(Stacktrace) ->
582
+ Indent = "\n ",
583
+ lists:foldl(
584
+ fun(Entry, Acc) ->
585
+ Acc ++ Indent ++ error_logger_lager_h:format_mfa(Entry)
586
+ end,
587
+ [],
588
+ lists:reverse(Stacktrace)).
589
+
590
+pr_stacktrace(Stacktrace, {Class, Reason}) ->
591
+ lists:flatten(
592
+ pr_stacktrace(Stacktrace) ++ "\n" ++ io_lib:format("~s:~p", [Class, Reason])).
593
+
594
+rotate_sink(Sink) ->
595
+ Handlers = lager_config:global_get(handlers),
596
+ RotateHandlers = lists:filtermap(
597
+ fun({Handler,_,S}) when S == Sink -> {true, {Handler, Sink}};
598
+ (_) -> false
599
+ end,
600
+ Handlers),
601
+ rotate_handlers(RotateHandlers).
602
+
603
+rotate_all() ->
604
+ rotate_handlers(lists:map(fun({H,_,S}) -> {H, S} end,
605
+ lager_config:global_get(handlers))).
606
+
607
+
608
+rotate_handlers(Handlers) ->
609
+ [ rotate_handler(Handler, Sink) || {Handler, Sink} <- Handlers ].
610
+
611
+
612
+rotate_handler(Handler) ->
613
+ Handlers = lager_config:global_get(handlers),
614
+ case lists:keyfind(Handler, 1, Handlers) of
615
+ {Handler, _, Sink} -> rotate_handler(Handler, Sink);
616
+ false -> ok
617
+ end.
618
+
619
+rotate_handler(Handler, Sink) ->
620
+ gen_event:call(Sink, Handler, rotate, ?ROTATE_TIMEOUT).
621
lager-2.1.0.tar.gz/src/lager_app.erl -> lager-3.1.0.tar.gz/src/lager_app.erl
Changed
318
1
2
-endif.
3
-export([start/0,
4
start/2,
5
+ start_handler/3,
6
stop/1]).
7
8
+-define(FILENAMES, '__lager_file_backend_filenames').
9
+-define(THROTTLE, lager_backend_throttle).
10
+-define(DEFAULT_HANDLER_CONF,
11
+ [{lager_console_backend, info},
12
+ {lager_file_backend,
13
+ [{file, "log/error.log"}, {level, error},
14
+ {size, 10485760}, {date, "$D0"}, {count, 5}]
15
+ },
16
+ {lager_file_backend,
17
+ [{file, "log/console.log"}, {level, info},
18
+ {size, 10485760}, {date, "$D0"}, {count, 5}]
19
+ }
20
+ ]).
21
+
22
start() ->
23
application:start(lager).
24
25
-start(_StartType, _StartArgs) ->
26
- {ok, Pid} = lager_sup:start_link(),
27
+start_throttle(Sink, Threshold, Window) ->
28
+ _ = supervisor:start_child(lager_handler_watcher_sup,
29
+ [Sink, ?THROTTLE, [Threshold, Window]]),
30
+ ok.
31
32
+determine_async_behavior(_Sink, {ok, undefined}, _Window) ->
33
+ ok;
34
+determine_async_behavior(_Sink, undefined, _Window) ->
35
+ ok;
36
+determine_async_behavior(_Sink, {ok, Threshold}, _Window) when not is_integer(Threshold) orelse Threshold < 0 ->
37
+ error_logger:error_msg("Invalid value for 'async_threshold': ~p~n",
38
+ [Threshold]),
39
+ throw({error, bad_config});
40
+determine_async_behavior(Sink, {ok, Threshold}, undefined) ->
41
+ start_throttle(Sink, Threshold, erlang:trunc(Threshold * 0.2));
42
+determine_async_behavior(_Sink, {ok, Threshold}, {ok, Window}) when not is_integer(Window) orelse Window > Threshold orelse Window < 0 ->
43
+ error_logger:error_msg(
44
+ "Invalid value for 'async_threshold_window': ~p~n", [Window]),
45
+ throw({error, bad_config});
46
+determine_async_behavior(Sink, {ok, Threshold}, {ok, Window}) ->
47
+ start_throttle(Sink, Threshold, Window).
48
49
- case application:get_env(lager, async_threshold) of
50
- undefined ->
51
- ok;
52
- {ok, undefined} ->
53
- undefined;
54
- {ok, Threshold} when is_integer(Threshold), Threshold >= 0 ->
55
- DefWindow = erlang:trunc(Threshold * 0.2), % maybe 0?
56
- ThresholdWindow =
57
- case application:get_env(lager, async_threshold_window) of
58
+start_handlers(_Sink, undefined) ->
59
+ ok;
60
+start_handlers(_Sink, Handlers) when not is_list(Handlers) ->
61
+ error_logger:error_msg(
62
+ "Invalid value for 'handlers' (must be list): ~p~n", [Handlers]),
63
+ throw({error, bad_config});
64
+start_handlers(Sink, Handlers) ->
65
+ %% handlers failing to start are handled in the handler_watcher
66
+ lager_config:global_set(handlers,
67
+ lager_config:global_get(handlers, []) ++
68
+ lists:map(fun({Module, Config}) ->
69
+ check_handler_config(Module, Config),
70
+ start_handler(Sink, Module, Config);
71
+ (_) ->
72
+ throw({error, bad_config})
73
+ end,
74
+ expand_handlers(Handlers))),
75
+ ok.
76
+
77
+start_handler(Sink, Module, Config) ->
78
+ {ok, Watcher} = supervisor:start_child(lager_handler_watcher_sup,
79
+ [Sink, Module, Config]),
80
+ {Module, Watcher, Sink}.
81
+
82
+check_handler_config({lager_file_backend, F}, Config) when is_list(Config) ->
83
+ Fs = case get(?FILENAMES) of
84
+ undefined -> ordsets:new();
85
+ X -> X
86
+ end,
87
+ case ordsets:is_element(F, Fs) of
88
+ true ->
89
+ error_logger:error_msg(
90
+ "Cannot have same file (~p) in multiple file backends~n", [F]),
91
+ throw({error, bad_config});
92
+ false ->
93
+ put(?FILENAMES,
94
+ ordsets:add_element(F, Fs))
95
+ end,
96
+ ok;
97
+check_handler_config(_Handler, Config) when is_list(Config) orelse is_atom(Config) ->
98
+ ok;
99
+check_handler_config(Handler, _BadConfig) ->
100
+ throw({error, {bad_config, Handler}}).
101
+
102
+clean_up_config_checks() ->
103
+ erase(?FILENAMES).
104
+
105
+interpret_hwm(undefined) ->
106
+ undefined;
107
+interpret_hwm({ok, undefined}) ->
108
+ undefined;
109
+interpret_hwm({ok, HWM}) when not is_integer(HWM) orelse HWM < 0 ->
110
+ _ = lager:log(warning, self(), "Invalid error_logger high water mark: ~p, disabling", [HWM]),
111
+ undefined;
112
+interpret_hwm({ok, HWM}) ->
113
+ HWM.
114
+
115
+start_error_logger_handler({ok, false}, _HWM, _Whitelist) ->
116
+ [];
117
+start_error_logger_handler(_, HWM, undefined) ->
118
+ start_error_logger_handler(ignore_me, HWM, {ok, []});
119
+start_error_logger_handler(_, HWM, {ok, WhiteList}) ->
120
+ GlStrategy = case application:get_env(lager, error_logger_groupleader_strategy) of
121
undefined ->
122
- DefWindow;
123
- {ok, Window} when is_integer(Window), Window < Threshold, Window >= 0 ->
124
- Window;
125
- {ok, BadWindow} ->
126
+ handle;
127
+ {ok, GlStrategy0} when
128
+ GlStrategy0 =:= handle;
129
+ GlStrategy0 =:= ignore;
130
+ GlStrategy0 =:= mirror ->
131
+ GlStrategy0;
132
+ {ok, BadGlStrategy} ->
133
error_logger:error_msg(
134
- "Invalid value for 'async_threshold_window': ~p~n", [BadWindow]),
135
+ "Invalid value for 'error_logger_groupleader_strategy': ~p~n",
136
+ [BadGlStrategy]),
137
throw({error, bad_config})
138
end,
139
- _ = supervisor:start_child(lager_handler_watcher_sup,
140
- [lager_event, lager_backend_throttle, [Threshold, ThresholdWindow]]),
141
- ok;
142
- {ok, BadThreshold} ->
143
- error_logger:error_msg("Invalid value for 'async_threshold': ~p~n", [BadThreshold]),
144
- throw({error, bad_config})
145
- end,
146
147
- Handlers = case application:get_env(lager, handlers) of
148
- undefined ->
149
- [{lager_console_backend, info},
150
- {lager_file_backend, [{file, "log/error.log"}, {level, error}, {size, 10485760}, {date, "$D0"}, {count, 5}]},
151
- {lager_file_backend, [{file, "log/console.log"}, {level, info}, {size, 10485760}, {date, "$D0"}, {count, 5}]}];
152
- {ok, Val} ->
153
- Val
154
- end,
155
+ case supervisor:start_child(lager_handler_watcher_sup, [error_logger, error_logger_lager_h, [HWM, GlStrategy]]) of
156
+ {ok, _} ->
157
+ [begin error_logger:delete_report_handler(X), X end ||
158
+ X <- gen_event:which_handlers(error_logger) -- [error_logger_lager_h | WhiteList]];
159
+ {error, _} ->
160
+ []
161
+ end.
162
163
- %% handlers failing to start are handled in the handler_watcher
164
- _ = [supervisor:start_child(lager_handler_watcher_sup, [lager_event, Module, Config]) ||
165
- {Module, Config} <- expand_handlers(Handlers)],
166
+%% `determine_async_behavior/3' is called with the results from either
167
+%% `application:get_env/2' and `proplists:get_value/2'. Since
168
+%% `application:get_env/2' wraps a successful retrieval in an `{ok,
169
+%% Value}' tuple, do the same for the result from
170
+%% `proplists:get_value/2'.
171
+wrap_proplist_value(undefined) ->
172
+ undefined;
173
+wrap_proplist_value(Value) ->
174
+ {ok, Value}.
175
176
- ok = add_configured_traces(),
177
+configure_sink(Sink, SinkDef) ->
178
+ lager_config:new_sink(Sink),
179
+ ChildId = lager_util:make_internal_sink_name(Sink),
180
+ _ = supervisor:start_child(lager_sup,
181
+ {ChildId,
182
+ {gen_event, start_link,
183
+ [{local, Sink}]},
184
+ permanent, 5000, worker, dynamic}),
185
+ determine_async_behavior(Sink,
186
+ wrap_proplist_value(
187
+ proplists:get_value(async_threshold, SinkDef)),
188
+ wrap_proplist_value(
189
+ proplists:get_value(async_threshold_window, SinkDef))
190
+ ),
191
+ start_handlers(Sink,
192
+ proplists:get_value(handlers, SinkDef, [])),
193
194
- %% mask the messages we have no use for
195
- lager:update_loglevel_config(),
196
-
197
- HighWaterMark = case application:get_env(lager, error_logger_hwm) of
198
- {ok, undefined} ->
199
- undefined;
200
- {ok, HwmVal} when is_integer(HwmVal), HwmVal > 0 ->
201
- HwmVal;
202
- {ok, BadVal} ->
203
- _ = lager:log(warning, self(), "Invalid error_logger high water mark: ~p, disabling", [BadVal]),
204
- undefined;
205
- undefined ->
206
- undefined
207
- end,
208
+ lager:update_loglevel_config(Sink).
209
210
- SavedHandlers =
211
- case application:get_env(lager, error_logger_redirect) of
212
- {ok, false} ->
213
- [];
214
- _ ->
215
- WhiteList = case application:get_env(lager, error_logger_whitelist) of
216
- undefined ->
217
- [];
218
- {ok, WhiteList0} ->
219
- WhiteList0
220
- end,
221
222
- case supervisor:start_child(lager_handler_watcher_sup, [error_logger, error_logger_lager_h, [HighWaterMark]]) of
223
- {ok, _} ->
224
- [begin error_logger:delete_report_handler(X), X end ||
225
- X <- gen_event:which_handlers(error_logger) -- [error_logger_lager_h | WhiteList]];
226
- {error, _} ->
227
- []
228
- end
229
- end,
230
+configure_extra_sinks(Sinks) ->
231
+ lists:foreach(fun({Sink, Proplist}) -> configure_sink(Sink, Proplist) end,
232
+ Sinks).
233
+
234
+%% R15 doesn't know about application:get_env/3
235
+get_env(Application, Key, Default) ->
236
+ get_env_default(application:get_env(Application, Key),
237
+ Default).
238
+
239
+get_env_default(undefined, Default) ->
240
+ Default;
241
+get_env_default({ok, Value}, _Default) ->
242
+ Value.
243
+
244
+start(_StartType, _StartArgs) ->
245
+ {ok, Pid} = lager_sup:start_link(),
246
+
247
+ %% Handle the default sink.
248
+ determine_async_behavior(?DEFAULT_SINK,
249
+ application:get_env(lager, async_threshold),
250
+ application:get_env(lager, async_threshold_window)),
251
+ start_handlers(?DEFAULT_SINK,
252
+ get_env(lager, handlers, ?DEFAULT_HANDLER_CONF)),
253
+
254
+
255
+ lager:update_loglevel_config(?DEFAULT_SINK),
256
+
257
+ SavedHandlers = start_error_logger_handler(
258
+ application:get_env(lager, error_logger_redirect),
259
+ interpret_hwm(application:get_env(lager, error_logger_hwm)),
260
+ application:get_env(lager, error_logger_whitelist)
261
+ ),
262
263
- _ = lager_util:trace_filter(none),
264
+ _ = lager_util:trace_filter(none),
265
+
266
+ %% Now handle extra sinks
267
+ configure_extra_sinks(get_env(lager, extra_sinks, [])),
268
+
269
+ ok = add_configured_traces(),
270
+
271
+ clean_up_config_checks(),
272
273
{ok, Pid, SavedHandlers}.
274
275
276
277
maybe_make_handler_id(Mod, Config) ->
278
%% Allow the backend to generate a gen_event handler id, if it wants to.
279
- %% We don't use erlang:function_exported here because that requires the module
280
+ %% We don't use erlang:function_exported here because that requires the module
281
%% already be loaded, which is unlikely at this phase of startup. Using code:load
282
- %% caused undesireable side-effects with generating code-coverage reports.
283
+ %% caused undesirable side-effects with generating code-coverage reports.
284
try Mod:config_to_id(Config) of
285
Id ->
286
{Id, Config}
287
288
)
289
}
290
].
291
+
292
+check_handler_config_test_() ->
293
+ Good = expand_handlers(?DEFAULT_HANDLER_CONF),
294
+ Bad = expand_handlers([{lager_console_backend, info},
295
+ {lager_file_backend, [{file, "same_file.log"}]},
296
+ {lager_file_backend, [{file, "same_file.log"}, {level, info}]}]),
297
+ AlsoBad = [{lager_logstash_backend,
298
+ {level, info},
299
+ {output, {udp, "localhost", 5000}},
300
+ {format, json},
301
+ {json_encoder, jiffy}}],
302
+ BadToo = [{fail, {fail}}],
303
+ [
304
+ {"lager_file_backend_good",
305
+ ?_assertEqual([ok, ok, ok], [ check_handler_config(M,C) || {M,C} <- Good ])
306
+ },
307
+ {"lager_file_backend_bad",
308
+ ?_assertThrow({error, bad_config}, [ check_handler_config(M,C) || {M,C} <- Bad ])
309
+ },
310
+ {"Invalid config dies",
311
+ ?_assertThrow({error, bad_config}, start_handlers(foo, AlsoBad))
312
+ },
313
+ {"Invalid config dies",
314
+ ?_assertThrow({error, {bad_config, _}}, start_handlers(foo, BadToo))
315
+ }
316
+ ].
317
-endif.
318
lager-2.1.0.tar.gz/src/lager_backend_throttle.erl -> lager-3.1.0.tar.gz/src/lager_backend_throttle.erl
Changed
65
1
2
-export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2,
3
code_change/3]).
4
5
+%%
6
+%% Allow test code to verify that we're doing the needful.
7
+-ifdef(TEST).
8
+-define(ETS_TABLE, async_threshold_test).
9
+-define(TOGGLE_SYNC(), test_increment(sync_toggled)).
10
+-define(TOGGLE_ASYNC(), test_increment(async_toggled)).
11
+-else.
12
+-define(TOGGLE_SYNC(), true).
13
+-define(TOGGLE_ASYNC(), true).
14
+-endif.
15
+
16
-record(state, {
17
+ sink :: atom(),
18
hwm :: non_neg_integer(),
19
window_min :: non_neg_integer(),
20
async = true :: boolean()
21
}).
22
23
-init([Hwm, Window]) ->
24
- lager_config:set(async, true),
25
- {ok, #state{hwm=Hwm, window_min=Hwm - Window}}.
26
+init([{sink, Sink}, Hwm, Window]) ->
27
+ lager_config:set({Sink, async}, true),
28
+ {ok, #state{sink=Sink, hwm=Hwm, window_min=Hwm - Window}}.
29
30
31
handle_call(get_loglevel, State) ->
32
33
case {Len > State#state.hwm, Len < State#state.window_min, State#state.async} of
34
{true, _, true} ->
35
%% need to flip to sync mode
36
- lager_config:set(async, false),
37
+ ?TOGGLE_SYNC(),
38
+ lager_config:set({State#state.sink, async}, false),
39
{ok, State#state{async=false}};
40
{_, true, false} ->
41
%% need to flip to async mode
42
- lager_config:set(async, true),
43
+ ?TOGGLE_ASYNC(),
44
+ lager_config:set({State#state.sink, async}, true),
45
{ok, State#state{async=true}};
46
_ ->
47
%% nothing needs to change
48
49
code_change(_OldVsn, State, _Extra) ->
50
{ok, State}.
51
52
+-ifdef(TEST).
53
+test_get(Key) ->
54
+ get_default(ets:lookup(?ETS_TABLE, Key)).
55
+
56
+test_increment(Key) ->
57
+ ets:insert(?ETS_TABLE,
58
+ {Key, test_get(Key) + 1}).
59
+
60
+get_default([]) ->
61
+ 0;
62
+get_default([{_Key, Value}]) ->
63
+ Value.
64
+-endif.
65
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
20
1
2
3
bounce(Level) ->
4
_ = application:stop(lager),
5
- lager:start(),
6
- gen_event:add_handler(lager_event, lager_common_test_backend, [Level, false]),
7
- %lager:set_loglevel(lager_common_test_backend, Level),
8
+ application:set_env(lager, suppress_application_start_stop, true),
9
+ application:set_env(lager, handlers,
10
+ [
11
+ {lager_common_test_backend, [Level, false]}
12
+ ]),
13
+ ok = lager:start(),
14
+ %% we care more about getting all of our messages here than being
15
+ %% careful with the amount of memory that we're using.
16
+ error_logger_lager_h:set_high_water(100000),
17
ok.
18
19
-spec(init(integer()|atom()|[term()]) -> {ok, #state{}} | {error, atom()}).
20
lager-2.1.0.tar.gz/src/lager_config.erl -> lager-3.1.0.tar.gz/src/lager_config.erl
Changed
83
1
2
3
-include("lager.hrl").
4
5
--export([new/0, get/1, get/2, set/2]).
6
+-export([new/0, new_sink/1, get/1, get/2, set/2,
7
+ global_get/1, global_get/2, global_set/2]).
8
9
-define(TBL, lager_config).
10
+-define(GLOBAL, '_global').
11
+
12
+%% For multiple sinks, the key is now the registered event name and the old key
13
+%% as a tuple.
14
+%%
15
+%% {{lager_event, loglevel}, Value} instead of {loglevel, Value}
16
17
new() ->
18
%% set up the ETS configuration table
19
20
error:badarg ->
21
?INT_LOG(warning, "Table ~p already exists", [?TBL])
22
end,
23
+ new_sink(?DEFAULT_SINK),
24
+ %% Need to be able to find the `lager_handler_watcher' for all handlers
25
+ ets:insert_new(?TBL, {{?GLOBAL, handlers}, []}),
26
+ ok.
27
+
28
+new_sink(Sink) ->
29
%% use insert_new here so that if we're in an appup we don't mess anything up
30
%%
31
%% until lager is completely started, allow all messages to go through
32
- ets:insert_new(?TBL, {loglevel, {element(2, lager_util:config_to_mask(debug)), []}}),
33
- ok.
34
+ ets:insert_new(?TBL, {{Sink, loglevel}, {element(2, lager_util:config_to_mask(debug)), []}}).
35
+
36
+global_get(Key) ->
37
+ global_get(Key, undefined).
38
+
39
+global_get(Key, Default) ->
40
+ get({?GLOBAL, Key}, Default).
41
42
+global_set(Key, Value) ->
43
+ set({?GLOBAL, Key}, Value).
44
45
+
46
+get({_Sink, _Key}=FullKey) ->
47
+ get(FullKey, undefined);
48
get(Key) ->
49
- case ets:lookup(?TBL, Key) of
50
- [] ->
51
- undefined;
52
- [{Key, Res}] ->
53
- Res
54
- end.
55
+ get({?DEFAULT_SINK, Key}, undefined).
56
57
-get(Key, Default) ->
58
- try ?MODULE:get(Key) of
59
- undefined ->
60
+get({Sink, Key}, Default) ->
61
+ try
62
+ case ets:lookup(?TBL, {Sink, Key}) of
63
+ [] ->
64
Default;
65
- Res ->
66
+ [{{Sink, Key}, Res}] ->
67
Res
68
+ end
69
catch
70
_:_ ->
71
Default
72
- end.
73
+ end;
74
+get(Key, Default) ->
75
+ get({?DEFAULT_SINK, Key}, Default).
76
77
+set({Sink, Key}, Value) ->
78
+ ets:insert(?TBL, {{Sink, Key}, Value});
79
set(Key, Value) ->
80
- ets:insert(?TBL, {Key, Value}).
81
-
82
+ set({?DEFAULT_SINK, Key}, Value).
83
lager-2.1.0.tar.gz/src/lager_console_backend.erl -> lager-3.1.0.tar.gz/src/lager_console_backend.erl
Changed
81
1
2
-define(TERSE_FORMAT,[time, " ", color, "[", severity,"] ", message]).
3
4
%% @private
5
+init([Level]) when is_atom(Level) ->
6
+ init(Level);
7
init([Level, true]) -> % for backwards compatibility
8
init([Level,{lager_default_formatter,[{eol, eol()}]}]);
9
init([Level,false]) -> % for backwards compatibility
10
11
init(Level) ->
12
init([Level,{lager_default_formatter,?TERSE_FORMAT ++ [eol()]}]).
13
14
-
15
%% @private
16
handle_call(get_loglevel, #state{level=Level} = State) ->
17
{ok, Level, State};
18
19
register(user, Pid),
20
erlang:group_leader(Pid, whereis(lager_event)),
21
gen_event:add_handler(lager_event, lager_console_backend, info),
22
- lager_config:set(loglevel, {element(2, lager_util:config_to_mask(info)), []}),
23
+ lager_config:set({lager_event, loglevel}, {element(2, lager_util:config_to_mask(info)), []}),
24
lager:log(info, self(), "Test message"),
25
receive
26
{io_request, From, ReplyAs, {put_chars, unicode, Msg}} ->
27
28
register(user, Pid),
29
erlang:group_leader(Pid, whereis(lager_event)),
30
gen_event:add_handler(lager_event, lager_console_backend, [info, true]),
31
- lager_config:set(loglevel, {element(2, lager_util:config_to_mask(info)), []}),
32
+ lager_config:set({lager_event, loglevel}, {element(2, lager_util:config_to_mask(info)), []}),
33
lager:info("Test message"),
34
PidStr = pid_to_list(self()),
35
receive
36
37
gen_event:add_handler(lager_event, lager_console_backend,
38
[info, {lager_default_formatter, [date,"#",time,"#",severity,"#",node,"#",pid,"#",
39
module,"#",function,"#",file,"#",line,"#",message,"\r\n"]}]),
40
- lager_config:set(loglevel, {?INFO, []}),
41
+ lager_config:set({lager_event, loglevel}, {?INFO, []}),
42
lager:info("Test message"),
43
PidStr = pid_to_list(self()),
44
NodeStr = atom_to_list(node()),
45
46
register(user, Pid),
47
gen_event:add_handler(lager_event, lager_console_backend, info),
48
erlang:group_leader(Pid, whereis(lager_event)),
49
- lager_config:set(loglevel, {element(2, lager_util:config_to_mask(info)), []}),
50
+ lager_config:set({lager_event, loglevel}, {element(2, lager_util:config_to_mask(info)), []}),
51
lager:debug("Test message"),
52
receive
53
{io_request, From, ReplyAs, {put_chars, unicode, _Msg}} ->
54
55
unregister(user),
56
register(user, Pid),
57
gen_event:add_handler(lager_event, lager_console_backend, info),
58
- lager_config:set(loglevel, {element(2, lager_util:config_to_mask(info)), []}),
59
+ lager_config:set({lager_event, loglevel}, {element(2, lager_util:config_to_mask(info)), []}),
60
erlang:group_leader(Pid, whereis(lager_event)),
61
lager:debug("Test message"),
62
receive
63
64
unregister(user),
65
register(user, Pid),
66
gen_event:add_handler(lager_event, lager_console_backend, info),
67
- lager_config:set(loglevel, {element(2, lager_util:config_to_mask(info)), []}),
68
+ lager_config:set({lager_event, loglevel}, {element(2, lager_util:config_to_mask(info)), []}),
69
lager:set_loglevel(lager_console_backend, '!=info'),
70
erlang:group_leader(Pid, whereis(lager_event)),
71
lager:debug("Test message"),
72
73
unregister(user),
74
register(user, Pid),
75
gen_event:add_handler(lager_event, lager_console_backend, info),
76
- lager_config:set(loglevel, {element(2, lager_util:config_to_mask(info)), []}),
77
+ lager_config:set({lager_event, loglevel}, {element(2, lager_util:config_to_mask(info)), []}),
78
lager:set_loglevel(lager_console_backend, '=debug'),
79
erlang:group_leader(Pid, whereis(lager_event)),
80
lager:debug("Test message"),
81
lager-2.1.0.tar.gz/src/lager_crash_log.erl -> lager-3.1.0.tar.gz/src/lager_crash_log.erl
Changed
11
1
2
Date, Count], []).
3
4
%% @private
5
-init([Filename, MaxBytes, Size, Date, Count]) ->
6
+init([RelFilename, MaxBytes, Size, Date, Count]) ->
7
+ Filename = lager_util:expand_path(RelFilename),
8
case lager_util:open_logfile(Filename, false) of
9
{ok, {FD, Inode, _}} ->
10
schedule_rotation(Date),
11
lager-2.1.0.tar.gz/src/lager_default_formatter.erl -> lager-3.1.0.tar.gz/src/lager_default_formatter.erl
Changed
272
1
2
%% or refer to other properties, if desired. You can also use a {atom, semi-iolist(), semi-iolist()} formatter, which
3
%% acts like a ternary operator's true/false branches.
4
%%
5
-%% The metadata properties date,time, message, and severity will always exist.
6
+%% The metadata properties date,time, message, severity, and sev will always exist.
7
%% The properties pid, file, line, module, and function will always exist if the parser transform is used.
8
%%
9
%% Example:
10
11
%%
12
%% `[{pid,"Unknown Pid"}]' -> "?.?.?" if pid is in the metadata, "Unknown Pid" if not.
13
%%
14
-%% `[{pid, ["My pid is ", pid], "Unknown Pid"}]' -> if pid is in the metada print "My pid is ?.?.?", otherwise print "Unknown Pid"
15
+%% `[{pid, ["My pid is ", pid], ["Unknown Pid"]}]' -> if pid is in the metada print "My pid is ?.?.?", otherwise print "Unknown Pid"
16
%% @end
17
-spec format(lager_msg:lager_msg(),list(),list()) -> any().
18
format(Msg,[], Colors) ->
19
20
T;
21
output(severity,Msg) ->
22
atom_to_list(lager_msg:severity(Msg));
23
+output(blank,_Msg) ->
24
+ output({blank," "},_Msg);
25
+output({blank,Fill},_Msg) ->
26
+ Fill;
27
+output(sev,Msg) ->
28
+ %% Write brief acronym for the severity level (e.g. debug -> $D)
29
+ [lager_util:level_to_chr(lager_msg:severity(Msg))];
30
+output(metadata, Msg) ->
31
+ output({metadata, "=", " "}, Msg);
32
+output({metadata, IntSep, FieldSep}, Msg) ->
33
+ MD = lists:keysort(1, lager_msg:metadata(Msg)),
34
+ string:join([io_lib:format("~s~s~p", [K, IntSep, V]) || {K, V} <- MD], FieldSep);
35
output(Prop,Msg) when is_atom(Prop) ->
36
Metadata = lager_msg:metadata(Msg),
37
make_printable(get_metadata(Prop,Metadata,<<"Undefined">>));
38
39
_ ->
40
[ output(V, Msg) || V <- Present]
41
end;
42
+output({Prop, Present, Absent, Width}, Msg) when is_atom(Prop) ->
43
+ %% sort of like a poor man's ternary operator
44
+ Metadata = lager_msg:metadata(Msg),
45
+ case get_metadata(Prop, Metadata) of
46
+ undefined ->
47
+ [ output(V, Msg, Width) || V <- Absent];
48
+ _ ->
49
+ [ output(V, Msg, Width) || V <- Present]
50
+ end;
51
output(Other,_) -> make_printable(Other).
52
53
+output(message, Msg, _Width) -> lager_msg:message(Msg);
54
+output(date,Msg, _Width) ->
55
+ {D, _T} = lager_msg:datetime(Msg),
56
+ D;
57
+output(time, Msg, _Width) ->
58
+ {_D, T} = lager_msg:datetime(Msg),
59
+ T;
60
+output(severity, Msg, Width) ->
61
+ make_printable(atom_to_list(lager_msg:severity(Msg)), Width);
62
+output(sev,Msg, _Width) ->
63
+ %% Write brief acronym for the severity level (e.g. debug -> $D)
64
+ [lager_util:level_to_chr(lager_msg:severity(Msg))];
65
+output(blank,_Msg, _Width) ->
66
+ output({blank, " "},_Msg, _Width);
67
+output({blank, Fill},_Msg, _Width) ->
68
+ Fill;
69
+output(metadata, Msg, _Width) ->
70
+ output({metadata, "=", " "}, Msg, _Width);
71
+output({metadata, IntSep, FieldSep}, Msg, _Width) ->
72
+ MD = lists:keysort(1, lager_msg:metadata(Msg)),
73
+ [string:join([io_lib:format("~s~s~p", [K, IntSep, V]) || {K, V} <- MD], FieldSep)];
74
+
75
+output(Prop, Msg, Width) when is_atom(Prop) ->
76
+ Metadata = lager_msg:metadata(Msg),
77
+ make_printable(get_metadata(Prop,Metadata,<<"Undefined">>), Width);
78
+output({Prop,Default},Msg, Width) when is_atom(Prop) ->
79
+ Metadata = lager_msg:metadata(Msg),
80
+ make_printable(get_metadata(Prop,Metadata,output(Default,Msg)), Width);
81
+output(Other,_, Width) -> make_printable(Other, Width).
82
+
83
output_color(_Msg,[]) -> [];
84
output_color(Msg,Colors) ->
85
Level = lager_msg:severity(Msg),
86
87
make_printable(L) when is_list(L) orelse is_binary(L) -> L;
88
make_printable(Other) -> io_lib:format("~p",[Other]).
89
90
+make_printable(A,W) when is_integer(W)-> string:left(make_printable(A),W);
91
+make_printable(A,{Align,W}) when is_integer(W) ->
92
+ case Align of
93
+ left ->
94
+ string:left(make_printable(A),W);
95
+ centre ->
96
+ string:centre(make_printable(A),W);
97
+ right ->
98
+ string:right(make_printable(A),W);
99
+ _ ->
100
+ string:left(make_printable(A),W)
101
+ end;
102
+
103
+make_printable(A,_W) -> make_printable(A).
104
+
105
get_metadata(Key, Metadata) ->
106
get_metadata(Key, Metadata, undefined).
107
108
109
[date, " ", time," [",severity,"] ",pid, " ", message, "\n"]
110
)))
111
},
112
- {"Non existant metadata can default to string",
113
+ {"Non existent metadata can default to string",
114
?_assertEqual(iolist_to_binary([Date, " ", Time, " [error] Fallback Message\n"]),
115
iolist_to_binary(format(lager_msg:new("Message",
116
Now,
117
118
[date, " ", time," [",severity,"] ",{does_not_exist,"Fallback"}, " ", message, "\n"]
119
)))
120
},
121
- {"Non existant metadata can default to other metadata",
122
+ {"Non existent metadata can default to other metadata",
123
?_assertEqual(iolist_to_binary([Date, " ", Time, " [error] Fallback Message\n"]),
124
iolist_to_binary(format(lager_msg:new("Message",
125
Now,
126
127
[]),
128
[date, " ", time," [",severity,"] ",{does_not_exist,pid}, " ", message, "\n"]
129
)))
130
+ },
131
+ {"Non existent metadata can default to a string2",
132
+ ?_assertEqual(iolist_to_binary(["Unknown Pid"]),
133
+ iolist_to_binary(format(lager_msg:new("Message",
134
+ Now,
135
+ error,
136
+ [],
137
+ []),
138
+ [{pid, ["My pid is ", pid], ["Unknown Pid"]}]
139
+ )))
140
+ },
141
+ {"Metadata can have extra formatting",
142
+ ?_assertEqual(iolist_to_binary(["My pid is hello"]),
143
+ iolist_to_binary(format(lager_msg:new("Message",
144
+ Now,
145
+ error,
146
+ [{pid, hello}],
147
+ []),
148
+ [{pid, ["My pid is ", pid], ["Unknown Pid"]}]
149
+ )))
150
+ },
151
+ {"Metadata can have extra formatting1",
152
+ ?_assertEqual(iolist_to_binary(["servername"]),
153
+ iolist_to_binary(format(lager_msg:new("Message",
154
+ Now,
155
+ error,
156
+ [{pid, hello}, {server, servername}],
157
+ []),
158
+ [{server,{pid, ["(", pid, ")"], ["(Unknown Server)"]}}]
159
+ )))
160
+ },
161
+ {"Metadata can have extra formatting2",
162
+ ?_assertEqual(iolist_to_binary(["(hello)"]),
163
+ iolist_to_binary(format(lager_msg:new("Message",
164
+ Now,
165
+ error,
166
+ [{pid, hello}],
167
+ []),
168
+ [{server,{pid, ["(", pid, ")"], ["(Unknown Server)"]}}]
169
+ )))
170
+ },
171
+ {"Metadata can have extra formatting3",
172
+ ?_assertEqual(iolist_to_binary(["(Unknown Server)"]),
173
+ iolist_to_binary(format(lager_msg:new("Message",
174
+ Now,
175
+ error,
176
+ [],
177
+ []),
178
+ [{server,{pid, ["(", pid, ")"], ["(Unknown Server)"]}}]
179
+ )))
180
+ },
181
+ {"Metadata can be printed in its enterity",
182
+ ?_assertEqual(iolist_to_binary(["bar=2 baz=3 foo=1"]),
183
+ iolist_to_binary(format(lager_msg:new("Message",
184
+ Now,
185
+ error,
186
+ [{foo, 1}, {bar, 2}, {baz, 3}],
187
+ []),
188
+ [metadata]
189
+ )))
190
+ },
191
+ {"Metadata can be printed in its enterity with custom seperators",
192
+ ?_assertEqual(iolist_to_binary(["bar->2, baz->3, foo->1"]),
193
+ iolist_to_binary(format(lager_msg:new("Message",
194
+ Now,
195
+ error,
196
+ [{foo, 1}, {bar, 2}, {baz, 3}],
197
+ []),
198
+ [{metadata, "->", ", "}]
199
+ )))
200
+ },
201
+ {"Metadata can have extra formatting with width 1",
202
+ ?_assertEqual(iolist_to_binary(["(hello )(hello )(hello)(hello)(hello)"]),
203
+ iolist_to_binary(format(lager_msg:new("Message",
204
+ Now,
205
+ error,
206
+ [{pid, hello}],
207
+ []),
208
+ ["(",{pid, [pid], "", 10},")",
209
+ "(",{pid, [pid], "", {bad_align,10}},")",
210
+ "(",{pid, [pid], "", bad10},")",
211
+ "(",{pid, [pid], "", {right,bad20}},")",
212
+ "(",{pid, [pid], "", {bad_align,bad20}},")"]
213
+ )))
214
+ },
215
+ {"Metadata can have extra formatting with width 2",
216
+ ?_assertEqual(iolist_to_binary(["(hello )"]),
217
+ iolist_to_binary(format(lager_msg:new("Message",
218
+ Now,
219
+ error,
220
+ [{pid, hello}],
221
+ []),
222
+ ["(",{pid, [pid], "", {left,10}},")"]
223
+ )))
224
+ },
225
+ {"Metadata can have extra formatting with width 3",
226
+ ?_assertEqual(iolist_to_binary(["( hello)"]),
227
+ iolist_to_binary(format(lager_msg:new("Message",
228
+ Now,
229
+ error,
230
+ [{pid, hello}],
231
+ []),
232
+ ["(",{pid, [pid], "", {right,10}},")"]
233
+ )))
234
+ },
235
+ {"Metadata can have extra formatting with width 4",
236
+ ?_assertEqual(iolist_to_binary(["( hello )"]),
237
+ iolist_to_binary(format(lager_msg:new("Message",
238
+ Now,
239
+ error,
240
+ [{pid, hello}],
241
+ []),
242
+ ["(",{pid, [pid], "", {centre,10}},")"]
243
+ )))
244
+ },
245
+ {"Metadata can have extra formatting with width 5",
246
+ ?_assertEqual(iolist_to_binary(["error |hello ! ( hello )"]),
247
+ iolist_to_binary(format(lager_msg:new("Message",
248
+ Now,
249
+ error,
250
+ [{pid, hello}],
251
+ []),
252
+ [{x,"",[severity,{blank,"|"},pid], 10},"!",blank,"(",{pid, [pid], "", {centre,10}},")"]
253
+ )))
254
+ },
255
+ {"Metadata can have extra formatting with width 6",
256
+ ?_assertEqual(iolist_to_binary([Time,Date," bar=2 baz=3 foo=1 pid=hello EMessage"]),
257
+ iolist_to_binary(format(lager_msg:new("Message",
258
+ Now,
259
+ error,
260
+ [{pid, hello},{foo, 1}, {bar, 2}, {baz, 3}],
261
+ []),
262
+ [{x,"",[time]}, {x,"",[date],20},blank,{x,"",[metadata],30},blank,{x,"",[sev],10},message, {message,message,"", {right,20}}]
263
+ )))
264
}
265
+
266
+
267
+
268
+
269
].
270
271
-endif.
272
lager-2.1.0.tar.gz/src/lager_file_backend.erl -> lager-3.1.0.tar.gz/src/lager_file_backend.erl
Changed
263
1
2
size = 0 :: integer(),
3
date :: undefined | string(),
4
count = 10 :: integer(),
5
+ shaper :: lager_shaper(),
6
formatter :: atom(),
7
formatter_config :: any(),
8
sync_on :: {'mask', integer()},
9
10
11
-type option() :: {file, string()} | {level, lager:log_level()} |
12
{size, non_neg_integer()} | {date, string()} |
13
- {count, non_neg_integer()} | {sync_interval, non_neg_integer()} |
14
+ {count, non_neg_integer()} | {high_water_mark, non_neg_integer()} |
15
+ {sync_interval, non_neg_integer()} |
16
{sync_size, non_neg_integer()} | {sync_on, lager:log_level()} |
17
{check_interval, non_neg_integer()} | {formatter, atom()} |
18
{formatter_config, term()}.
19
20
-spec init([option(),...]) -> {ok, #state{}} | {error, bad_config}.
21
init({FileName, LogLevel}) when is_list(FileName), is_atom(LogLevel) ->
22
- %% backwards compatability hack
23
+ %% backwards compatibility hack
24
init([{file, FileName}, {level, LogLevel}]);
25
init({FileName, LogLevel, Size, Date, Count}) when is_list(FileName), is_atom(LogLevel) ->
26
- %% backwards compatability hack
27
+ %% backwards compatibility hack
28
init([{file, FileName}, {level, LogLevel}, {size, Size}, {date, Date}, {count, Count}]);
29
init([{FileName, LogLevel, Size, Date, Count}, {Formatter,FormatterConfig}]) when is_list(FileName), is_atom(LogLevel), is_atom(Formatter) ->
30
- %% backwards compatability hack
31
+ %% backwards compatibility hack
32
init([{file, FileName}, {level, LogLevel}, {size, Size}, {date, Date}, {count, Count}, {formatter, Formatter}, {formatter_config, FormatterConfig}]);
33
init([LogFile,{Formatter}]) ->
34
- %% backwards compatability hack
35
+ %% backwards compatibility hack
36
init([LogFile,{Formatter,[]}]);
37
init([{FileName, LogLevel}, {Formatter,FormatterConfig}]) when is_list(FileName), is_atom(LogLevel), is_atom(Formatter) ->
38
- %% backwards compatability hack
39
+ %% backwards compatibility hack
40
init([{file, FileName}, {level, LogLevel}, {formatter, Formatter}, {formatter_config, FormatterConfig}]);
41
init(LogFileConfig) when is_list(LogFileConfig) ->
42
case validate_logfile_proplist(LogFileConfig) of
43
44
{error, {fatal, bad_config}};
45
Config ->
46
%% probabably a better way to do this, but whatever
47
- [Name, Level, Date, Size, Count, SyncInterval, SyncSize, SyncOn, CheckInterval, Formatter, FormatterConfig] =
48
- [proplists:get_value(Key, Config) || Key <- [file, level, date, size, count, sync_interval, sync_size, sync_on, check_interval, formatter, formatter_config]],
49
+ [RelName, Level, Date, Size, Count, HighWaterMark, SyncInterval, SyncSize, SyncOn, CheckInterval, Formatter, FormatterConfig] =
50
+ [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]],
51
+ Name = lager_util:expand_path(RelName),
52
schedule_rotation(Name, Date),
53
- State0 = #state{name=Name, level=Level, size=Size, date=Date, count=Count, formatter=Formatter,
54
+ Shaper = #lager_shaper{hwm=HighWaterMark},
55
+ State0 = #state{name=Name, level=Level, size=Size, date=Date, count=Count, shaper=Shaper, formatter=Formatter,
56
formatter_config=FormatterConfig, sync_on=SyncOn, sync_interval=SyncInterval, sync_size=SyncSize,
57
check_interval=CheckInterval},
58
State = case lager_util:open_logfile(Name, {SyncSize, SyncInterval}) of
59
60
end;
61
handle_call(get_loglevel, #state{level=Level} = State) ->
62
{ok, Level, State};
63
+handle_call({set_loghwm, Hwm}, #state{shaper=Shaper, name=Name} = State) ->
64
+ case validate_logfile_proplist([{file, Name}, {high_water_mark, Hwm}]) of
65
+ false ->
66
+ {ok, {error, bad_log_hwm}, State};
67
+ _ ->
68
+ NewShaper = Shaper#lager_shaper{hwm=Hwm},
69
+ ?INT_LOG(notice, "Changed loghwm of ~s to ~p", [Name, Hwm]),
70
+ {ok, {last_loghwm, Shaper#lager_shaper.hwm}, State#state{shaper=NewShaper}}
71
+ end;
72
+handle_call(rotate, State = #state{name=File}) ->
73
+ {ok, NewState} = handle_info({rotate, File}, State),
74
+ {ok, ok, NewState};
75
handle_call(_Request, State) ->
76
{ok, ok, State}.
77
78
%% @private
79
handle_event({log, Message},
80
- #state{name=Name, level=L,formatter=Formatter,formatter_config=FormatConfig} = State) ->
81
+ #state{name=Name, level=L, shaper=Shaper, formatter=Formatter,formatter_config=FormatConfig} = State) ->
82
case lager_util:is_loggable(Message,L,{lager_file_backend, Name}) of
83
true ->
84
- {ok,write(State, lager_msg:timestamp(Message), lager_msg:severity_as_int(Message), Formatter:format(Message,FormatConfig)) };
85
+ case lager_util:check_hwm(Shaper) of
86
+ {true, Drop, #lager_shaper{hwm=Hwm} = NewShaper} ->
87
+ NewState = case Drop > 0 of
88
+ true ->
89
+ Report = io_lib:format(
90
+ "lager_file_backend dropped ~p messages in the last second that exceeded the limit of ~p messages/sec",
91
+ [Drop, Hwm]),
92
+ ReportMsg = lager_msg:new(Report, warning, [], []),
93
+ write(State, lager_msg:timestamp(ReportMsg),
94
+ lager_msg:severity_as_int(ReportMsg), Formatter:format(ReportMsg, FormatConfig));
95
+ false ->
96
+ State
97
+ end,
98
+ {ok,write(NewState#state{shaper=NewShaper},
99
+ lager_msg:timestamp(Message), lager_msg:severity_as_int(Message),
100
+ Formatter:format(Message,FormatConfig))};
101
+ {false, _, NewShaper} ->
102
+ {ok, State#state{shaper=NewShaper}}
103
+ end;
104
false ->
105
{ok, State}
106
end;
107
108
%% @private
109
handle_info({rotate, File}, #state{name=File,count=Count,date=Date} = State) ->
110
_ = lager_util:rotate_logfile(File, Count),
111
+ State1 = close_file(State),
112
schedule_rotation(File, Date),
113
- {ok, State};
114
+ {ok, State1};
115
handle_info(_Info, State) ->
116
{ok, State}.
117
118
%% @private
119
-terminate(_Reason, #state{fd=FD}) ->
120
- %% flush and close any file handles
121
- _ = file:datasync(FD),
122
- _ = file:close(FD),
123
+terminate(_Reason, State) ->
124
+ %% leaving this function call unmatched makes dialyzer cranky
125
+ _ = close_file(State),
126
ok.
127
128
%% @private
129
code_change(_OldVsn, State, _Extra) ->
130
{ok, State}.
131
132
-%% @private convert the config into a gen_event handler ID
133
+%% Convert the config into a gen_event handler ID
134
config_to_id({Name,_Severity}) when is_list(Name) ->
135
{?MODULE, Name};
136
config_to_id({Name,_Severity,_Size,_Rotation,_Count}) ->
137
138
Flap
139
end,
140
State#state{flap=Flap2};
141
- _ ->
142
+ _ ->
143
State
144
end.
145
146
147
_ ->
148
throw({bad_config, "Invalid rotation count", Count})
149
end;
150
+validate_logfile_proplist([{high_water_mark, HighWaterMark}|Tail], Acc) ->
151
+ case HighWaterMark of
152
+ Hwm when is_integer(Hwm), Hwm >= 0 ->
153
+ validate_logfile_proplist(Tail, [{high_water_mark, Hwm}|Acc]);
154
+ _ ->
155
+ throw({bad_config, "Invalid high water mark", HighWaterMark})
156
+ end;
157
validate_logfile_proplist([{date, Date}|Tail], Acc) ->
158
case lager_util:parse_rotation_date_spec(Date) of
159
{ok, Spec} ->
160
161
erlang:send_after(lager_util:calculate_next_rotation(Date) * 1000, self(), {rotate, Name}),
162
ok.
163
164
+close_file(#state{fd=undefined} = State) ->
165
+ State;
166
+close_file(#state{fd=FD} = State) ->
167
+ %% Flush and close any file handles.
168
+ _ = file:datasync(FD),
169
+ _ = file:close(FD),
170
+ State#state{fd=undefined}.
171
+
172
-ifdef(TEST).
173
174
get_loglevel_test() ->
175
176
?assert(filelib:is_regular("test.log.0"))
177
end
178
},
179
+ {"rotation call should work",
180
+ fun() ->
181
+ gen_event:add_handler(lager_event, {lager_file_backend, "test.log"}, [{file, "test.log"}, {level, info}, {check_interval, 1000}]),
182
+ lager:log(error, self(), "Test message1"),
183
+ lager:log(error, self(), "Test message1"),
184
+ gen_event:call(lager_event, {lager_file_backend, "test.log"}, rotate, infinity),
185
+ lager:log(error, self(), "Test message1"),
186
+ ?assert(filelib:is_regular("test.log.0"))
187
+ end
188
+ },
189
{"sync_on option should work",
190
fun() ->
191
gen_event:add_handler(lager_event, lager_file_backend, [{file, "test.log"}, {level, info}, {sync_on, "=info"}, {check_interval, 5000}, {sync_interval, 5000}]),
192
193
{"test.log", critical}),
194
lager:error("Test message"),
195
?assertEqual({ok, <<>>}, file:read_file("test.log")),
196
- {Level, _} = lager_config:get(loglevel),
197
- lager_config:set(loglevel, {Level, [{[{module,
198
+ {Level, _} = lager_config:get({lager_event, loglevel}),
199
+ lager_config:set({lager_event, loglevel}, {Level, [{[{module,
200
?MODULE}], ?DEBUG,
201
{lager_file_backend, "test.log"}}]}),
202
lager:error("Test message"),
203
204
{ok, Bin1} = file:read_file("test.log"),
205
?assertMatch([_, _, "[critical]", _, "Test message\n"], re:split(Bin1, " ", [{return, list}, {parts, 5}])),
206
ok = file:delete("test.log"),
207
- {Level, _} = lager_config:get(loglevel),
208
- lager_config:set(loglevel, {Level, [{[{module,
209
+ {Level, _} = lager_config:get({lager_event, loglevel}),
210
+ lager_config:set({lager_event, loglevel}, {Level, [{[{module,
211
?MODULE}], ?DEBUG,
212
{lager_file_backend, "test.log"}}]}),
213
lager:critical("Test message"),
214
215
?assertMatch([_, _, "[error]", _, "Test message\n"], re:split(Bin3, " ", [{return, list}, {parts, 5}]))
216
end
217
},
218
+ {"tracing to a dedicated file should work even if root_log is set",
219
+ fun() ->
220
+ {ok, P} = file:get_cwd(),
221
+ file:delete(P ++ "/test_root_log/foo.log"),
222
+ application:set_env(lager, log_root, P++"/test_root_log"),
223
+ {ok, _} = lager:trace_file("foo.log", [{module, ?MODULE}]),
224
+ lager:error("Test message"),
225
+ %% not elegible for trace
226
+ lager:log(error, self(), "Test message"),
227
+ {ok, Bin3} = file:read_file(P++"/test_root_log/foo.log"),
228
+ application:unset_env(lager, log_root),
229
+ ?assertMatch([_, _, "[error]", _, "Test message\n"], re:split(Bin3, " ", [{return, list}, {parts, 5}]))
230
+ end
231
+ },
232
{"tracing with options should work",
233
fun() ->
234
file:delete("foo.log"),
235
- {ok, _} = lager:trace_file("foo.log", [{module, ?MODULE}], [{size, 20}, {check_interval, 1}]),
236
+ {ok, _} = lager:trace_file("foo.log", [{module, ?MODULE}], [{size, 20}, {check_interval, 1}]),
237
lager:error("Test message"),
238
?assertNot(filelib:is_regular("foo.log.0")),
239
+ %% rotation is sensitive to intervals between
240
+ %% writes so we sleep to exceed the 1
241
+ %% millisecond interval specified by
242
+ %% check_interval above
243
+ timer:sleep(2),
244
lager:error("Test message"),
245
timer:sleep(10),
246
?assert(filelib:is_regular("foo.log.0"))
247
248
?_assertEqual(false,
249
validate_logfile_proplist([{file, "test.log"}, {count, infinity}]))
250
},
251
+ {"bad high water mark",
252
+ ?_assertEqual(false,
253
+ validate_logfile_proplist([{file, "test.log"}, {high_water_mark, infinity}]))
254
+ },
255
{"bad date",
256
?_assertEqual(false,
257
validate_logfile_proplist([{file, "test.log"}, {date, "midnight"}]))
258
259
260
261
-endif.
262
-
263
lager-2.1.0.tar.gz/src/lager_handler_watcher.erl -> lager-3.1.0.tar.gz/src/lager_handler_watcher.erl
Changed
92
1
2
-record(state, {
3
module :: atom(),
4
config :: any(),
5
- event :: pid() | atom()
6
+ sink :: pid() | atom()
7
}).
8
9
-start_link(Event, Module, Config) ->
10
- gen_server:start_link(?MODULE, [Event, Module, Config], []).
11
+start_link(Sink, Module, Config) ->
12
+ gen_server:start_link(?MODULE, [Sink, Module, Config], []).
13
14
-start(Event, Module, Config) ->
15
- gen_server:start(?MODULE, [Event, Module, Config], []).
16
+start(Sink, Module, Config) ->
17
+ gen_server:start(?MODULE, [Sink, Module, Config], []).
18
19
-init([Event, Module, Config]) ->
20
- install_handler(Event, Module, Config),
21
- {ok, #state{event=Event, module=Module, config=Config}}.
22
+init([Sink, Module, Config]) ->
23
+ install_handler(Sink, Module, Config),
24
+ {ok, #state{sink=Sink, module=Module, config=Config}}.
25
26
handle_call(_Call, _From, State) ->
27
{reply, ok, State}.
28
29
handle_info({gen_event_EXIT, Module, shutdown}, #state{module=Module} = State) ->
30
{stop, normal, State};
31
handle_info({gen_event_EXIT, Module, Reason}, #state{module=Module,
32
- config=Config, event=Event} = State) ->
33
+ config=Config, sink=Sink} = State) ->
34
case lager:log(error, self(), "Lager event handler ~p exited with reason ~s",
35
[Module, error_logger_lager_h:format_reason(Reason)]) of
36
ok ->
37
- install_handler(Event, Module, Config);
38
+ install_handler(Sink, Module, Config);
39
{error, _} ->
40
%% lager is not working, so installing a handler won't work
41
ok
42
end,
43
{noreply, State};
44
-handle_info(reinstall_handler, #state{module=Module, config=Config, event=Event} = State) ->
45
- install_handler(Event, Module, Config),
46
+handle_info(reinstall_handler, #state{module=Module, config=Config, sink=Sink} = State) ->
47
+ install_handler(Sink, Module, Config),
48
{noreply, State};
49
handle_info(stop, State) ->
50
{stop, normal, State};
51
52
{ok, State}.
53
54
%% internal
55
-
56
-install_handler(Event, Module, Config) ->
57
- case gen_event:add_sup_handler(Event, Module, Config) of
58
+install_handler(Sink, lager_backend_throttle, Config) ->
59
+ %% The lager_backend_throttle needs to know to which sink it is
60
+ %% attached, hence this admittedly ugly workaround. Handlers are
61
+ %% sensitive to the structure of the configuration sent to `init',
62
+ %% sadly, so it's not trivial to add a configuration item to be
63
+ %% ignored to backends without breaking 3rd party handlers.
64
+ install_handler2(Sink, lager_backend_throttle, [{sink, Sink}|Config]);
65
+install_handler(Sink, Module, Config) ->
66
+ install_handler2(Sink, Module, Config).
67
+
68
+%% private
69
+install_handler2(Sink, Module, Config) ->
70
+ case gen_event:add_sup_handler(Sink, Module, Config) of
71
ok ->
72
- ?INT_LOG(debug, "Lager installed handler ~p into ~p", [Module, Event]),
73
- lager:update_loglevel_config(),
74
+ ?INT_LOG(debug, "Lager installed handler ~p into ~p", [Module, Sink]),
75
+ lager:update_loglevel_config(Sink),
76
ok;
77
{error, {fatal, Reason}} ->
78
?INT_LOG(error, "Lager fatally failed to install handler ~p into"
79
- " ~p, NOT retrying: ~p", [Module, Event, Reason]),
80
+ " ~p, NOT retrying: ~p", [Module, Sink, Reason]),
81
%% tell ourselves to stop
82
self() ! stop,
83
ok;
84
Error ->
85
%% try to reinstall it later
86
?INT_LOG(error, "Lager failed to install handler ~p into"
87
- " ~p, retrying later : ~p", [Module, Event, Error]),
88
+ " ~p, retrying later : ~p", [Module, Sink, Error]),
89
erlang:send_after(5000, self(), reinstall_handler),
90
ok
91
end.
92
lager-2.1.0.tar.gz/src/lager_stdlib.erl -> lager-3.1.0.tar.gz/src/lager_stdlib.erl
Changed
10
1
2
string_p(Term) ->
3
string_p1(Term).
4
5
-string_p1([H|T]) when is_integer(H), H >= $\s, H < 255 ->
6
+string_p1([H|T]) when is_integer(H), H >= $\s, H < 256 ->
7
string_p1(T);
8
string_p1([$\n|T]) -> string_p1(T);
9
string_p1([$\r|T]) -> string_p1(T);
10
lager-2.1.0.tar.gz/src/lager_sup.erl -> lager-3.1.0.tar.gz/src/lager_sup.erl
Changed
17
1
2
init([]) ->
3
%% set up the config, is safe even during relups
4
lager_config:new(),
5
+ %% TODO:
6
+ %% Always start lager_event as the default and make sure that
7
+ %% other gen_event stuff can start up as needed
8
+ %%
9
+ %% Maybe a new API to handle the sink and its policy?
10
Children = [
11
{lager, {gen_event, start_link, [{local, lager_event}]},
12
- permanent, 5000, worker, [dynamic]},
13
+ permanent, 5000, worker, dynamic},
14
{lager_handler_watcher_sup, {lager_handler_watcher_sup, start_link, []},
15
permanent, 5000, supervisor, [lager_handler_watcher_sup]}],
16
17
lager-2.1.0.tar.gz/src/lager_transform.erl -> lager-3.1.0.tar.gz/src/lager_transform.erl
Changed
302
1
2
parse_transform(AST, Options) ->
3
TruncSize = proplists:get_value(lager_truncation_size, Options, ?DEFAULT_TRUNCATION),
4
Enable = proplists:get_value(lager_print_records_flag, Options, true),
5
+ Sinks = [lager] ++ proplists:get_value(lager_extra_sinks, Options, []),
6
put(print_records_flag, Enable),
7
put(truncation_size, TruncSize),
8
+ put(sinks, Sinks),
9
erlang:put(records, []),
10
%% .app file should either be in the outdir, or the same dir as the source file
11
guess_application(proplists:get_value(outdir, Options), hd(AST)),
12
13
walk_body(Acc, []) ->
14
lists:reverse(Acc);
15
walk_body(Acc, [H|T]) ->
16
- walk_body([transform_statement(H)|Acc], T).
17
+ walk_body([transform_statement(H, get(sinks))|Acc], T).
18
19
-transform_statement({call, Line, {remote, _Line1, {atom, _Line2, lager},
20
- {atom, _Line3, Severity}}, Arguments0} = Stmt) ->
21
- case lists:member(Severity, ?LEVELS) of
22
+transform_statement({call, Line, {remote, _Line1, {atom, _Line2, Module},
23
+ {atom, _Line3, Function}}, Arguments0} = Stmt,
24
+ Sinks) ->
25
+ case lists:member(Module, Sinks) of
26
true ->
27
- SeverityAsInt=lager_util:level_to_num(Severity),
28
- DefaultAttrs0 = {cons, Line, {tuple, Line, [
29
- {atom, Line, module}, {atom, Line, get(module)}]},
30
- {cons, Line, {tuple, Line, [
31
- {atom, Line, function}, {atom, Line, get(function)}]},
32
- {cons, Line, {tuple, Line, [
33
- {atom, Line, line},
34
- {integer, Line, Line}]},
35
- {cons, Line, {tuple, Line, [
36
- {atom, Line, pid},
37
- {call, Line, {atom, Line, pid_to_list}, [
38
- {call, Line, {atom, Line ,self}, []}]}]},
39
- {cons, Line, {tuple, Line, [
40
- {atom, Line, node},
41
- {call, Line, {atom, Line, node}, []}]},
42
- %% get the metadata with lager:md(), this will always return a list so we can use it as the tail here
43
- {call, Line, {remote, Line, {atom, Line, lager}, {atom, Line, md}}, []}}}}}},
44
- %{nil, Line}}}}}}},
45
- DefaultAttrs = case erlang:get(application) of
46
- undefined ->
47
- DefaultAttrs0;
48
- App ->
49
- %% stick the application in the attribute list
50
- concat_lists({cons, Line, {tuple, Line, [
51
- {atom, Line, application},
52
- {atom, Line, App}]},
53
- {nil, Line}}, DefaultAttrs0)
54
- end,
55
- {Traces, Message, Arguments} = case Arguments0 of
56
- [Format] ->
57
- {DefaultAttrs, Format, {atom, Line, none}};
58
- [Arg1, Arg2] ->
59
- %% some ambiguity here, figure out if these arguments are
60
- %% [Format, Args] or [Attr, Format].
61
- %% The trace attributes will be a list of tuples, so check
62
- %% for that.
63
- case {element(1, Arg1), Arg1} of
64
- {_, {cons, _, {tuple, _, _}, _}} ->
65
- {concat_lists(Arg1, DefaultAttrs),
66
- Arg2, {atom, Line, none}};
67
- {Type, _} when Type == var;
68
- Type == lc;
69
- Type == call;
70
- Type == record_field ->
71
- %% crap, its not a literal. look at the second
72
- %% argument to see if it is a string
73
- case Arg2 of
74
- {string, _, _} ->
75
- {concat_lists(Arg1, DefaultAttrs),
76
- Arg2, {atom, Line, none}};
77
- _ ->
78
- %% not a string, going to have to guess
79
- %% it's the argument list
80
- {DefaultAttrs, Arg1, Arg2}
81
- end;
82
- _ ->
83
- {DefaultAttrs, Arg1, Arg2}
84
- end;
85
- [Attrs, Format, Args] ->
86
- {concat_lists(Attrs, DefaultAttrs), Format, Args}
87
- end,
88
- %% Generate some unique variable names so we don't accidentaly export from case clauses.
89
- %% Note that these are not actual atoms, but the AST treats variable names as atoms.
90
- LevelVar = make_varname("__Level", Line),
91
- TracesVar = make_varname("__Traces", Line),
92
- PidVar = make_varname("__Pid", Line),
93
- %% Wrap the call to lager_dispatch log in a case that will avoid doing any work if this message is not elegible for logging
94
- %% case {whereis(lager_event(lager_event), lager_config:get(loglevel, {?LOG_NONE, []})} of
95
- {'case', Line,
96
- {tuple, Line,
97
- [{call, Line, {atom, Line, whereis}, [{atom, Line, lager_event}]},
98
- {call, Line, {remote, Line, {atom, Line, lager_config}, {atom, Line, get}}, [{atom, Line, loglevel}, {tuple, Line, [{integer, Line, 0},{nil, Line}]}]}]},
99
- [
100
- %% {undefined, _} -> {error, lager_not_running}
101
- {clause, Line,
102
- [{tuple, Line, [{atom, Line, undefined}, {var, Line, '_'}]}],
103
- [],
104
- %% trick the linter into avoiding a 'term constructed by not used' error:
105
- %% (fun() -> {error, lager_not_running} end)();
106
- [{call, Line, {'fun', Line, {clauses, [{clause, Line, [],[], [{tuple, Line, [{atom, Line, error},{atom, Line, lager_not_running}]}]}]}}, []}]},
107
- %% If we care about the loglevel, or there's any traces installed, we have do more checking
108
- %% {Level, Traces} when (Level band SeverityAsInt) /= 0 orelse Traces /= [] ->
109
- {clause, Line,
110
- [{tuple, Line, [{var, Line, PidVar}, {tuple, Line, [{var, Line, LevelVar}, {var, Line, TracesVar}]}]}],
111
- [[{op, Line, 'orelse',
112
- {op, Line, '/=', {op, Line, 'band', {var, Line, LevelVar}, {integer, Line, SeverityAsInt}}, {integer, Line, 0}},
113
- {op, Line, '/=', {var, Line, TracesVar}, {nil, Line}}}]],
114
- [
115
- %% do the call to lager:dispatch_log
116
- {call, Line, {remote, Line, {atom, Line, lager}, {atom, Line, do_log}},
117
- [
118
- {atom,Line,Severity},
119
- Traces,
120
- Message,
121
- Arguments,
122
- {integer, Line, get(truncation_size)},
123
- {integer, Line, SeverityAsInt},
124
- {var, Line, LevelVar},
125
- {var, Line, TracesVar},
126
- {var, Line, PidVar}
127
- ]
128
- }
129
- ]},
130
- %% otherwise, do nothing
131
- %% _ -> ok
132
- {clause, Line, [{var, Line, '_'}],[],[{atom, Line, ok}]}
133
- ]};
134
+ case lists:member(Function, ?LEVELS) of
135
+ true ->
136
+ SinkName = lager_util:make_internal_sink_name(Module),
137
+ do_transform(Line, SinkName, Function, Arguments0);
138
+ false ->
139
+ case lists:keyfind(Function, 1, ?LEVELS_UNSAFE) of
140
+ {Function, Severity} ->
141
+ SinkName = lager_util:make_internal_sink_name(Module),
142
+ do_transform(Line, SinkName, Severity, Arguments0, unsafe);
143
+ false ->
144
+ Stmt
145
+ end
146
+ end;
147
false ->
148
- Stmt
149
+ list_to_tuple(transform_statement(tuple_to_list(Stmt), Sinks))
150
end;
151
-transform_statement({call, Line, {remote, Line1, {atom, Line2, boston_lager},
152
- {atom, Line3, Severity}}, Arguments}) ->
153
- NewArgs = case Arguments of
154
- [{string, L, Msg}] -> [{string, L, re:replace(Msg, "r", "h", [{return, list}, global])}];
155
- [{string, L, Format}, Args] -> [{string, L, re:replace(Format, "r", "h", [{return, list}, global])}, Args];
156
- Other -> Other
157
- end,
158
- transform_statement({call, Line, {remote, Line1, {atom, Line2, lager},
159
- {atom, Line3, Severity}}, NewArgs});
160
-transform_statement(Stmt) when is_tuple(Stmt) ->
161
- list_to_tuple(transform_statement(tuple_to_list(Stmt)));
162
-transform_statement(Stmt) when is_list(Stmt) ->
163
- [transform_statement(S) || S <- Stmt];
164
-transform_statement(Stmt) ->
165
+transform_statement(Stmt, Sinks) when is_tuple(Stmt) ->
166
+ list_to_tuple(transform_statement(tuple_to_list(Stmt), Sinks));
167
+transform_statement(Stmt, Sinks) when is_list(Stmt) ->
168
+ [transform_statement(S, Sinks) || S <- Stmt];
169
+transform_statement(Stmt, _Sinks) ->
170
Stmt.
171
172
+do_transform(Line, SinkName, Severity, Arguments0) ->
173
+ do_transform(Line, SinkName, Severity, Arguments0, safe).
174
+
175
+do_transform(Line, SinkName, Severity, Arguments0, Safety) ->
176
+ SeverityAsInt=lager_util:level_to_num(Severity),
177
+ DefaultAttrs0 = {cons, Line, {tuple, Line, [
178
+ {atom, Line, module}, {atom, Line, get(module)}]},
179
+ {cons, Line, {tuple, Line, [
180
+ {atom, Line, function}, {atom, Line, get(function)}]},
181
+ {cons, Line, {tuple, Line, [
182
+ {atom, Line, line},
183
+ {integer, Line, Line}]},
184
+ {cons, Line, {tuple, Line, [
185
+ {atom, Line, pid},
186
+ {call, Line, {atom, Line, pid_to_list}, [
187
+ {call, Line, {atom, Line ,self}, []}]}]},
188
+ {cons, Line, {tuple, Line, [
189
+ {atom, Line, node},
190
+ {call, Line, {atom, Line, node}, []}]},
191
+ %% get the metadata with lager:md(), this will always return a list so we can use it as the tail here
192
+ {call, Line, {remote, Line, {atom, Line, lager}, {atom, Line, md}}, []}}}}}},
193
+ %{nil, Line}}}}}}},
194
+ DefaultAttrs = case erlang:get(application) of
195
+ undefined ->
196
+ DefaultAttrs0;
197
+ App ->
198
+ %% stick the application in the attribute list
199
+ concat_lists({cons, Line, {tuple, Line, [
200
+ {atom, Line, application},
201
+ {atom, Line, App}]},
202
+ {nil, Line}}, DefaultAttrs0)
203
+ end,
204
+ {Meta, Message, Arguments} = case Arguments0 of
205
+ [Format] ->
206
+ {DefaultAttrs, Format, {atom, Line, none}};
207
+ [Arg1, Arg2] ->
208
+ %% some ambiguity here, figure out if these arguments are
209
+ %% [Format, Args] or [Attr, Format].
210
+ %% The trace attributes will be a list of tuples, so check
211
+ %% for that.
212
+ case {element(1, Arg1), Arg1} of
213
+ {_, {cons, _, {tuple, _, _}, _}} ->
214
+ {concat_lists(Arg1, DefaultAttrs),
215
+ Arg2, {atom, Line, none}};
216
+ {Type, _} when Type == var;
217
+ Type == lc;
218
+ Type == call;
219
+ Type == record_field ->
220
+ %% crap, its not a literal. look at the second
221
+ %% argument to see if it is a string
222
+ case Arg2 of
223
+ {string, _, _} ->
224
+ {concat_lists(Arg1, DefaultAttrs),
225
+ Arg2, {atom, Line, none}};
226
+ _ ->
227
+ %% not a string, going to have to guess
228
+ %% it's the argument list
229
+ {DefaultAttrs, Arg1, Arg2}
230
+ end;
231
+ _ ->
232
+ {DefaultAttrs, Arg1, Arg2}
233
+ end;
234
+ [Attrs, Format, Args] ->
235
+ {concat_lists(Attrs, DefaultAttrs), Format, Args}
236
+ end,
237
+ %% Generate some unique variable names so we don't accidentally export from case clauses.
238
+ %% Note that these are not actual atoms, but the AST treats variable names as atoms.
239
+ LevelVar = make_varname("__Level", Line),
240
+ TracesVar = make_varname("__Traces", Line),
241
+ PidVar = make_varname("__Pid", Line),
242
+ LogFun = case Safety of
243
+ safe ->
244
+ do_log;
245
+ unsafe ->
246
+ do_log_unsafe
247
+ end,
248
+ %% Wrap the call to lager:dispatch_log/6 in case that will avoid doing any work if this message is not elegible for logging
249
+ %% See lager.erl (lines 89-100) for lager:dispatch_log/6
250
+ %% case {whereis(Sink), whereis(?DEFAULT_SINK), lager_config:get({Sink, loglevel}, {?LOG_NONE, []})} of
251
+ {'case',Line,
252
+ {tuple,Line,
253
+ [{call,Line,{atom,Line,whereis},[{atom,Line,SinkName}]},
254
+ {call,Line,{atom,Line,whereis},[{atom,Line,?DEFAULT_SINK}]},
255
+ {call,Line,
256
+ {remote,Line,{atom,Line,lager_config},{atom,Line,get}},
257
+ [{tuple,Line,[{atom,Line,SinkName},{atom,Line,loglevel}]},
258
+ {tuple,Line,[{integer,Line,0},{nil,Line}]}]}]},
259
+ %% {undefined, undefined, _} -> {error, lager_not_running};
260
+ [{clause,Line,
261
+ [{tuple,Line,
262
+ [{atom,Line,undefined},{atom,Line,undefined},{var,Line,'_'}]}],
263
+ [],
264
+ %% trick the linter into avoiding a 'term constructed but not used' error:
265
+ %% (fun() -> {error, lager_not_running} end)()
266
+ [{call, Line, {'fun', Line, {clauses, [{clause, Line, [],[], [{tuple, Line, [{atom, Line, error},{atom, Line, lager_not_running}]}]}]}}, []}]
267
+ },
268
+ %% {undefined, _, _} -> {error, {sink_not_configured, Sink}};
269
+ {clause,Line,
270
+ [{tuple,Line,
271
+ [{atom,Line,undefined},{var,Line,'_'},{var,Line,'_'}]}],
272
+ [],
273
+ %% same trick as above to avoid linter error
274
+ [{call, Line, {'fun', Line, {clauses, [{clause, Line, [],[], [{tuple,Line, [{atom,Line,error}, {tuple,Line,[{atom,Line,sink_not_configured},{atom,Line,SinkName}]}]}]}]}}, []}]
275
+ },
276
+ %% {SinkPid, _, {Level, Traces}} when ... -> lager:do_log/9;
277
+ {clause,Line,
278
+ [{tuple,Line,
279
+ [{var,Line,PidVar},
280
+ {var,Line,'_'},
281
+ {tuple,Line,[{var,Line,LevelVar},{var,Line,TracesVar}]}]}],
282
+ [[{op, Line, 'orelse',
283
+ {op, Line, '/=', {op, Line, 'band', {var, Line, LevelVar}, {integer, Line, SeverityAsInt}}, {integer, Line, 0}},
284
+ {op, Line, '/=', {var, Line, TracesVar}, {nil, Line}}}]],
285
+ [{call,Line,{remote, Line, {atom, Line, lager}, {atom, Line, LogFun}},
286
+ [{atom,Line,Severity},
287
+ Meta,
288
+ Message,
289
+ Arguments,
290
+ {integer, Line, get(truncation_size)},
291
+ {integer, Line, SeverityAsInt},
292
+ {var, Line, LevelVar},
293
+ {var, Line, TracesVar},
294
+ {atom, Line, SinkName},
295
+ {var, Line, PidVar}]}]},
296
+ %% _ -> ok
297
+ {clause,Line,[{var,Line,'_'}],[],[{atom,Line,ok}]}]}.
298
+
299
make_varname(Prefix, Line) ->
300
list_to_atom(Prefix ++ atom_to_list(get(module)) ++ integer_to_list(Line)).
301
302
lager-2.1.0.tar.gz/src/lager_trunc_io.erl -> lager-3.1.0.tar.gz/src/lager_trunc_io.erl
Changed
148
1
2
%% compliance with the License. You should have received a copy of the
3
%% Erlang Public License along with your Erlang distribution. If not, it can be
4
%% retrieved via the world wide web at http://www.erlang.org/.
5
-%%
6
+%%
7
%% Software distributed under the License is distributed on an "AS IS"
8
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9
%% the License for the specific language governing rights and limitations
10
%% under the License.
11
-%%
12
+%%
13
%% The Initial Developer of the Original Code is Corelatus AB.
14
%% Portions created by Corelatus are Copyright 2003, Corelatus
15
%% AB. All Rights Reserved.''
16
17
18
-module(lager_trunc_io).
19
-author('matthias@corelatus.se').
20
-%% And thanks to Chris Newcombe for a bug fix
21
+%% And thanks to Chris Newcombe for a bug fix
22
-export([format/3, format/4, print/2, print/3, fprint/2, fprint/3, safe/2]). % interface functions
23
-version("$Id: trunc_io.erl,v 1.11 2009-02-23 12:01:06 matthias Exp $").
24
25
26
%% @doc Returns an flattened list containing the ASCII representation of the given
27
%% term.
28
-spec fprint(term(), pos_integer(), options()) -> string().
29
-fprint(T, Max, Options) ->
30
+fprint(T, Max, Options) ->
31
{L, _} = print(T, Max, prepare_options(Options, #print_options{})),
32
lists:flatten(L).
33
34
-%% @doc Same as print, but never crashes.
35
+%% @doc Same as print, but never crashes.
36
%%
37
%% This is a tradeoff. Print might conceivably crash if it's asked to
38
%% print something it doesn't understand, for example some new data
39
40
%% to io_lib to format the term, but then the formatting is
41
%% depth-limited instead of length limited, so you might run out
42
%% memory printing it. Out of the frying pan and into the fire.
43
-%%
44
+%%
45
-spec safe(term(), pos_integer()) -> {string(), pos_integer()} | {string()}.
46
safe(What, Len) ->
47
case catch print(What, Len) of
48
49
print(_, _, #print_options{depth=0}) -> {"...", 3};
50
51
52
-%% @doc We assume atoms, floats, funs, integers, PIDs, ports and refs never need
53
-%% to be truncated. This isn't strictly true, someone could make an
54
+%% @doc We assume atoms, floats, funs, integers, PIDs, ports and refs never need
55
+%% to be truncated. This isn't strictly true, someone could make an
56
%% arbitrarily long bignum. Let's assume that won't happen unless someone
57
%% is being malicious.
58
%%
59
60
SizeStr = integer_to_list(Size),
61
{[ValueStr, $:, SizeStr], length(ValueStr) + length(SizeStr) +1};
62
print(BitString, Max, Options) when is_bitstring(BitString) ->
63
- case byte_size(BitString) > Max of
64
+ BL = case byte_size(BitString) > Max of
65
true ->
66
- BL = binary_to_list(BitString, 1, Max);
67
+ binary_to_list(BitString, 1, Max);
68
_ ->
69
R = erlang:bitstring_to_list(BitString),
70
{Bytes, [Bits]} = lists:splitwith(fun erlang:is_integer/1, R),
71
%% tag the trailing bits with a special tuple we catch when
72
%% list_body calls print again
73
- BL = Bytes ++ [{inline_bitstring, Bits}]
74
+ Bytes ++ [{inline_bitstring, Bits}]
75
end,
76
{X, Len0} = list_body(BL, Max - 4, dec_depth(Options), true),
77
{["<<", X, ">>"], Len0 + 4};
78
79
{RC, Len} = record_fields(Fields, Max - length(Leader) + 1, dec_depth(Options)),
80
{[Leader, RC, "}"], Len + length(Leader) + 1};
81
82
-print(Tuple, Max, Options) when is_tuple(Tuple) ->
83
+print(Tuple, Max, Options) when is_tuple(Tuple) ->
84
{TC, Len} = tuple_contents(Tuple, Max-2, Options),
85
{[${, TC, $}], Len + 2};
86
87
88
false -> $|
89
end,
90
{[List ++ [Sep | "..."]], Len + 4};
91
-list_body([H|T], Max, Options, Tuple) ->
92
+list_body([H|T], Max, Options, Tuple) ->
93
{List, Len} = print(H, Max, Options),
94
{Final, FLen} = list_bodyc(T, Max - Len, Options, Tuple),
95
{[List|Final], FLen + Len};
96
97
list_bodyc(_, Max, _Options, _Tuple) when Max < 5 -> {",...", 4};
98
list_bodyc(_, _Max, #print_options{depth=1}, true) -> {",...", 4};
99
list_bodyc(_, _Max, #print_options{depth=1}, false) -> {"|...", 4};
100
-list_bodyc([H|T], Max, #print_options{depth=Depth} = Options, Tuple) ->
101
+list_bodyc([H|T], Max, #print_options{depth=Depth} = Options, Tuple) ->
102
{List, Len} = print(H, Max, dec_depth(Options)),
103
{Final, FLen} = list_bodyc(T, Max - Len - 1, dec_depth(Options), Tuple),
104
Sep = case Depth == 1 andalso not Tuple of
105
106
test(M,F),
107
perf(M,F,Reps-1);
108
perf(_,_,_) ->
109
- done.
110
+ done.
111
112
%% Performance test. Needs a particularly large term I saved as a binary...
113
-spec perf1() -> {non_neg_integer(), non_neg_integer()}.
114
115
?assertEqual("[\"foo\",98,97,114]", lists:flatten(format("~p", [["foo", $b, $a, $r]], 50))),
116
?assertEqual("[\"foo\",98,97,114]", lists:flatten(format("~P", [["foo", $b, $a, $r], 10], 50))),
117
?assertEqual("[[102,111,111],98,97,114]", lists:flatten(format("~w", [["foo", $b, $a, $r]], 50))),
118
-
119
+
120
%% complex ones
121
?assertEqual(" foobar", lists:flatten(format("~10s", [["foo", $b, $a, $r]], 50))),
122
?assertEqual("f", lists:flatten(format("~1s", [["foo", $b, $a, $r]], 50))),
123
124
?assertEqual("[1|...]", lists:flatten(format("~P", [[1, 2, 3], 2], 50))),
125
?assertEqual("[1,2|...]", lists:flatten(format("~P", [[1, 2, 3], 3], 50))),
126
?assertEqual("[1,2,3]", lists:flatten(format("~P", [[1, 2, 3], 4], 50))),
127
-
128
+
129
?assertEqual("{1,...}", lists:flatten(format("~P", [{1, 2, 3}, 2], 50))),
130
?assertEqual("{1,2,...}", lists:flatten(format("~P", [{1, 2, 3}, 3], 50))),
131
?assertEqual("{1,2,3}", lists:flatten(format("~P", [{1, 2, 3}, 4], 50))),
132
133
?assertEqual("[1,2|...]", lists:flatten(format("~P", [[1, 2, <<3>>], 3], 50))),
134
?assertEqual("[1,2,<<...>>]", lists:flatten(format("~P", [[1, 2, <<3>>], 4], 50))),
135
?assertEqual("[1,2,<<3>>]", lists:flatten(format("~P", [[1, 2, <<3>>], 5], 50))),
136
-
137
+
138
?assertEqual("<<...>>", lists:flatten(format("~P", [<<0, 0, 0, 0>>, 1], 50))),
139
?assertEqual("<<0,...>>", lists:flatten(format("~P", [<<0, 0, 0, 0>>, 2], 50))),
140
?assertEqual("<<0,0,...>>", lists:flatten(format("~P", [<<0, 0, 0, 0>>, 3], 50))),
141
?assertEqual("<<0,0,0,...>>", lists:flatten(format("~P", [<<0, 0, 0, 0>>, 4], 50))),
142
?assertEqual("<<0,0,0,0>>", lists:flatten(format("~P", [<<0, 0, 0, 0>>, 5], 50))),
143
-
144
+
145
%% this is a seriously weird edge case
146
?assertEqual("<<\" \"...>>", lists:flatten(format("~P", [<<32, 32, 32, 0>>, 2], 50))),
147
?assertEqual("<<\" \"...>>", lists:flatten(format("~P", [<<32, 32, 32, 0>>, 3], 50))),
148
lager-2.1.0.tar.gz/src/lager_util.erl -> lager-3.1.0.tar.gz/src/lager_util.erl
Changed
167
1
2
3
-include_lib("kernel/include/file.hrl").
4
5
--export([levels/0, level_to_num/1, num_to_level/1, config_to_mask/1, config_to_levels/1, mask_to_levels/1,
6
+-export([levels/0, level_to_num/1, level_to_chr/1,
7
+ num_to_level/1, config_to_mask/1, config_to_levels/1, mask_to_levels/1,
8
open_logfile/2, ensure_logfile/4, rotate_logfile/2, format_time/0, format_time/1,
9
localtime_ms/0, localtime_ms/1, maybe_utc/1, parse_rotation_date_spec/1,
10
calculate_next_rotation/1, validate_trace/1, check_traces/4, is_loggable/3,
11
- trace_filter/1, trace_filter/2]).
12
+ trace_filter/1, trace_filter/2, expand_path/1, check_hwm/1, make_internal_sink_name/1]).
13
14
-ifdef(TEST).
15
-include_lib("eunit/include/eunit.hrl").
16
17
levels() ->
18
[debug, info, notice, warning, error, critical, alert, emergency, none].
19
20
-level_to_num(debug) -> ?DEBUG;
21
-level_to_num(info) -> ?INFO;
22
-level_to_num(notice) -> ?NOTICE;
23
-level_to_num(warning) -> ?WARNING;
24
-level_to_num(error) -> ?ERROR;
25
-level_to_num(critical) -> ?CRITICAL;
26
-level_to_num(alert) -> ?ALERT;
27
-level_to_num(emergency) -> ?EMERGENCY;
28
-level_to_num(none) -> ?LOG_NONE.
29
-
30
-num_to_level(?DEBUG) -> debug;
31
-num_to_level(?INFO) -> info;
32
-num_to_level(?NOTICE) -> notice;
33
-num_to_level(?WARNING) -> warning;
34
-num_to_level(?ERROR) -> error;
35
-num_to_level(?CRITICAL) -> critical;
36
-num_to_level(?ALERT) -> alert;
37
+level_to_num(debug) -> ?DEBUG;
38
+level_to_num(info) -> ?INFO;
39
+level_to_num(notice) -> ?NOTICE;
40
+level_to_num(warning) -> ?WARNING;
41
+level_to_num(error) -> ?ERROR;
42
+level_to_num(critical) -> ?CRITICAL;
43
+level_to_num(alert) -> ?ALERT;
44
+level_to_num(emergency) -> ?EMERGENCY;
45
+level_to_num(none) -> ?LOG_NONE.
46
+
47
+level_to_chr(debug) -> $D;
48
+level_to_chr(info) -> $I;
49
+level_to_chr(notice) -> $N;
50
+level_to_chr(warning) -> $W;
51
+level_to_chr(error) -> $E;
52
+level_to_chr(critical) -> $C;
53
+level_to_chr(alert) -> $A;
54
+level_to_chr(emergency) -> $M;
55
+level_to_chr(none) -> $ .
56
+
57
+num_to_level(?DEBUG) -> debug;
58
+num_to_level(?INFO) -> info;
59
+num_to_level(?NOTICE) -> notice;
60
+num_to_level(?WARNING) -> warning;
61
+num_to_level(?ERROR) -> error;
62
+num_to_level(?CRITICAL) -> critical;
63
+num_to_level(?ALERT) -> alert;
64
num_to_level(?EMERGENCY) -> emergency;
65
-num_to_level(?LOG_NONE) -> none.
66
+num_to_level(?LOG_NONE) -> none.
67
68
-spec config_to_mask(atom()|string()) -> {'mask', integer()}.
69
config_to_mask(Conf) ->
70
71
i3l(I) when I < 100 -> [$0 | i2l(I)];
72
i3l(I) -> integer_to_list(I).
73
74
+%% When log_root option is provided, get the real path to a file
75
+expand_path(RelPath) ->
76
+ case application:get_env(lager, log_root) of
77
+ {ok, LogRoot} when is_list(LogRoot) -> % Join relative path
78
+ %% check if the given RelPath contains LogRoot, if so, do not add
79
+ %% it again; see gh #304
80
+ case string:str(filename:dirname(RelPath), LogRoot) of
81
+ X when X > 0 ->
82
+ RelPath;
83
+ _Zero ->
84
+ filename:join(LogRoot, RelPath)
85
+ end;
86
+ undefined -> % No log_root given, keep relative path
87
+ RelPath
88
+ end.
89
+
90
+%% Log rate limit, i.e. high water mark for incoming messages
91
+
92
+check_hwm(Shaper = #lager_shaper{hwm = undefined}) ->
93
+ {true, 0, Shaper};
94
+check_hwm(Shaper = #lager_shaper{mps = Mps, hwm = Hwm}) when Mps < Hwm ->
95
+ %% haven't hit high water mark yet, just log it
96
+ {true, 0, Shaper#lager_shaper{mps=Mps+1}};
97
+check_hwm(Shaper = #lager_shaper{lasttime = Last, dropped = Drop}) ->
98
+ %% are we still in the same second?
99
+ {M, S, _} = Now = os:timestamp(),
100
+ case Last of
101
+ {M, S, _} ->
102
+ %% still in same second, but have exceeded the high water mark
103
+ NewDrops = discard_messages(Now, 0),
104
+ {false, 0, Shaper#lager_shaper{dropped=Drop+NewDrops}};
105
+ _ ->
106
+ %% different second, reset all counters and allow it
107
+ {true, Drop, Shaper#lager_shaper{dropped = 0, mps=1, lasttime = Now}}
108
+ end.
109
+
110
+discard_messages(Second, Count) ->
111
+ {M, S, _} = os:timestamp(),
112
+ case Second of
113
+ {M, S, _} ->
114
+ receive
115
+ %% we only discard gen_event notifications, because
116
+ %% otherwise we might discard gen_event internal
117
+ %% messages, such as trapped EXITs
118
+ {notify, _Event} ->
119
+ discard_messages(Second, Count+1)
120
+ after 0 ->
121
+ Count
122
+ end;
123
+ _ ->
124
+ Count
125
+ end.
126
+
127
+%% @private Build an atom for the gen_event process based on a sink name.
128
+%% For historical reasons, the default gen_event process for lager itself is named
129
+%% `lager_event'. For all other sinks, it is SinkName++`_lager_event'
130
+make_internal_sink_name(lager) ->
131
+ ?DEFAULT_SINK;
132
+make_internal_sink_name(Sink) ->
133
+ list_to_atom(atom_to_list(Sink) ++ "_lager_event").
134
+
135
-ifdef(TEST).
136
137
parse_test() ->
138
139
?assertEqual([debug, notice, error], mask_to_levels(?DEBUG bor ?NOTICE bor ?ERROR)),
140
ok.
141
142
+expand_path_test() ->
143
+ OldRootVal = application:get_env(lager, log_root),
144
+
145
+ ok = application:unset_env(lager, log_root),
146
+ ?assertEqual("/foo/bar", expand_path("/foo/bar")),
147
+ ?assertEqual("foo/bar", expand_path("foo/bar")),
148
+
149
+ ok = application:set_env(lager, log_root, "log/dir"),
150
+ ?assertEqual("/foo/bar", expand_path("/foo/bar")), % Absolute path should not be changed
151
+ ?assertEqual("log/dir/foo/bar", expand_path("foo/bar")),
152
+ ?assertEqual("log/dir/foo/bar", expand_path("log/dir/foo/bar")), %% gh #304
153
+
154
+ case OldRootVal of
155
+ undefined -> application:unset_env(lager, log_root);
156
+ {ok, Root} -> application:set_env(lager, log_root, Root)
157
+ end,
158
+ ok.
159
+
160
+sink_name_test_() ->
161
+ [
162
+ ?_assertEqual(lager_event, make_internal_sink_name(lager)),
163
+ ?_assertEqual(audit_lager_event, make_internal_sink_name(audit))
164
+ ].
165
+
166
-endif.
167
lager-3.1.0.tar.gz/test/compress_pr_record_test.erl
Added
18
1
2
+-module(compress_pr_record_test).
3
+
4
+-compile([{parse_transform, lager_transform}]).
5
+
6
+-record(a, {field1, field2, foo, bar, baz, zyu, zix}).
7
+
8
+-ifdef(TEST).
9
+-include_lib("eunit/include/eunit.hrl").
10
+-endif.
11
+
12
+nested_record_test() ->
13
+ A = #a{field1 = "Notice me senpai"},
14
+ Pr_A = lager:pr(A, ?MODULE),
15
+ Pr_A_Comp = lager:pr(A, ?MODULE, [compress]),
16
+ ?assertMatch({'$lager_record', a, [{field1, "Notice me senpai"}, {field2, undefined} | _]}, Pr_A),
17
+ ?assertEqual({'$lager_record', a, [{field1, "Notice me senpai"}]}, Pr_A_Comp).
18
lager-2.1.0.tar.gz/test/crash.erl -> lager-3.1.0.tar.gz/test/crash.erl
Changed
12
1
2
-export([start/0]).
3
4
-record(state, {
5
- host,
6
- port
7
+ host :: term(),
8
+ port :: term()
9
}).
10
11
start() ->
12
lager-3.1.0.tar.gz/test/lager_rotate.erl
Added
140
1
2
+-module(lager_rotate).
3
+
4
+-compile(export_all).
5
+
6
+-ifdef(TEST).
7
+-include_lib("eunit/include/eunit.hrl").
8
+-endif.
9
+
10
+
11
+rotate_test_() ->
12
+ {foreach,
13
+ fun() ->
14
+ file:write_file("test1.log", ""),
15
+ file:write_file("test2.log", ""),
16
+ file:write_file("test3.log", ""),
17
+ file:delete("test1.log.0"),
18
+ file:delete("test2.log.0"),
19
+ file:delete("test3.log.0"),
20
+ error_logger:tty(false),
21
+ application:load(lager),
22
+ application:set_env(lager, handlers,
23
+ [{lager_file_backend, [{file, "test1.log"}, {level, info}]},
24
+ {lager_file_backend, [{file, "test2.log"}, {level, info}]}]),
25
+ application:set_env(lager, extra_sinks,
26
+ [{sink_event,
27
+ [{handlers,
28
+ [{lager_file_backend, [{file, "test3.log"}, {level, info}]}]}
29
+ ]}]),
30
+ application:set_env(lager, error_logger_redirect, false),
31
+ application:set_env(lager, async_threshold, undefined),
32
+ lager:start()
33
+ end,
34
+ fun(_) ->
35
+ file:delete("test1.log"),
36
+ file:delete("test2.log"),
37
+ file:delete("test3.log"),
38
+ file:delete("test1.log.0"),
39
+ file:delete("test2.log.0"),
40
+ file:delete("test3.log.0"),
41
+ application:stop(lager),
42
+ application:stop(goldrush),
43
+ error_logger:tty(true)
44
+ end,
45
+ [{"Rotate single file",
46
+ fun() ->
47
+ lager:log(error, self(), "Test message 1"),
48
+ lager:log(sink_event, error, self(), "Sink test message 1", []),
49
+ lager:rotate_handler({lager_file_backend, "test1.log"}),
50
+ timer:sleep(1000),
51
+ true = filelib:is_regular("test1.log.0"),
52
+ lager:log(error, self(), "Test message 2"),
53
+ lager:log(sink_event, error, self(), "Sink test message 2", []),
54
+
55
+ {ok, File1} = file:read_file("test1.log"),
56
+ {ok, File2} = file:read_file("test2.log"),
57
+ {ok, SinkFile} = file:read_file("test3.log"),
58
+ {ok, File1Old} = file:read_file("test1.log.0"),
59
+
60
+ have_no_log(File1, <<"Test message 1">>),
61
+ have_log(File1, <<"Test message 2">>),
62
+
63
+ have_log(File2, <<"Test message 1">>),
64
+ have_log(File2, <<"Test message 2">>),
65
+
66
+ have_log(File1Old, <<"Test message 1">>),
67
+ have_no_log(File1Old, <<"Test message 2">>),
68
+
69
+ have_log(SinkFile, <<"Sink test message 1">>),
70
+ have_log(SinkFile, <<"Sink test message 2">>)
71
+ end},
72
+ {"Rotate sink",
73
+ fun() ->
74
+ lager:log(error, self(), "Test message 1"),
75
+ lager:log(sink_event, error, self(), "Sink test message 1", []),
76
+ lager:rotate_sink(sink_event),
77
+ timer:sleep(1000),
78
+ true = filelib:is_regular("test3.log.0"),
79
+ lager:log(error, self(), "Test message 2"),
80
+ lager:log(sink_event, error, self(), "Sink test message 2", []),
81
+ {ok, File1} = file:read_file("test1.log"),
82
+ {ok, File2} = file:read_file("test2.log"),
83
+ {ok, SinkFile} = file:read_file("test3.log"),
84
+ {ok, SinkFileOld} = file:read_file("test3.log.0"),
85
+
86
+ have_log(File1, <<"Test message 1">>),
87
+ have_log(File1, <<"Test message 2">>),
88
+
89
+ have_log(File2, <<"Test message 1">>),
90
+ have_log(File2, <<"Test message 2">>),
91
+
92
+ have_log(SinkFileOld, <<"Sink test message 1">>),
93
+ have_no_log(SinkFileOld, <<"Sink test message 2">>),
94
+
95
+ have_no_log(SinkFile, <<"Sink test message 1">>),
96
+ have_log(SinkFile, <<"Sink test message 2">>)
97
+ end},
98
+ {"Rotate all",
99
+ fun() ->
100
+ lager:log(error, self(), "Test message 1"),
101
+ lager:log(sink_event, error, self(), "Sink test message 1", []),
102
+ lager:rotate_all(),
103
+ timer:sleep(1000),
104
+ true = filelib:is_regular("test3.log.0"),
105
+ lager:log(error, self(), "Test message 2"),
106
+ lager:log(sink_event, error, self(), "Sink test message 2", []),
107
+ {ok, File1} = file:read_file("test1.log"),
108
+ {ok, File2} = file:read_file("test2.log"),
109
+ {ok, SinkFile} = file:read_file("test3.log"),
110
+ {ok, File1Old} = file:read_file("test1.log.0"),
111
+ {ok, File2Old} = file:read_file("test2.log.0"),
112
+ {ok, SinkFileOld} = file:read_file("test3.log.0"),
113
+
114
+ have_no_log(File1, <<"Test message 1">>),
115
+ have_log(File1, <<"Test message 2">>),
116
+
117
+ have_no_log(File2, <<"Test message 1">>),
118
+ have_log(File2, <<"Test message 2">>),
119
+
120
+ have_no_log(SinkFile, <<"Sink test message 1">>),
121
+ have_log(SinkFile, <<"Sink test message 2">>),
122
+
123
+ have_log(SinkFileOld, <<"Sink test message 1">>),
124
+ have_no_log(SinkFileOld, <<"Sink test message 2">>),
125
+
126
+ have_log(File1Old, <<"Test message 1">>),
127
+ have_no_log(File1Old, <<"Test message 2">>),
128
+
129
+ have_log(File2Old, <<"Test message 1">>),
130
+ have_no_log(File2Old, <<"Test message 2">>)
131
+
132
+ end}]}.
133
+
134
+have_log(Data, Log) ->
135
+ {_,_} = binary:match(Data, Log).
136
+
137
+have_no_log(Data, Log) ->
138
+ nomatch = binary:match(Data, Log).
139
+
140
lager-2.1.0.tar.gz/test/lager_test_backend.erl -> lager-3.1.0.tar.gz/test/lager_test_backend.erl
Changed
1257
1
2
-%% Copyright (c) 2011-2012 Basho Technologies, Inc. All Rights Reserved.
3
+%% -------------------------------------------------------------------
4
+%%
5
+%% Copyright (c) 2011-2015 Basho Technologies, Inc.
6
%%
7
%% This file is provided to you under the Apache License,
8
%% Version 2.0 (the "License"); you may not use this file
9
10
%% KIND, either express or implied. See the License for the
11
%% specific language governing permissions and limitations
12
%% under the License.
13
+%%
14
+%% -------------------------------------------------------------------
15
16
-module(lager_test_backend).
17
18
19
-export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2,
20
code_change/3]).
21
22
--record(state, {level, buffer, ignored}).
23
--record(test, {attrs, format, args}).
24
--compile([{parse_transform, lager_transform}]).
25
+-define(TEST_SINK_NAME, '__lager_test_sink'). %% <-- used by parse transform
26
+-define(TEST_SINK_EVENT, '__lager_test_sink_lager_event'). %% <-- used by lager API calls and internals for gen_event
27
+
28
+-record(state, {level :: list(), buffer :: list(), ignored :: term()}).
29
+-compile({parse_transform, lager_transform}).
30
31
-ifdef(TEST).
32
-include_lib("eunit/include/eunit.hrl").
33
+-record(test, {attrs :: list(), format :: list(), args :: list()}).
34
-export([pop/0, count/0, count_ignored/0, flush/0, print_state/0]).
35
-endif.
36
37
38
-ifdef(TEST).
39
40
pop() ->
41
- gen_event:call(lager_event, ?MODULE, pop).
42
+ pop(lager_event).
43
44
count() ->
45
- gen_event:call(lager_event, ?MODULE, count).
46
+ count(lager_event).
47
48
count_ignored() ->
49
- gen_event:call(lager_event, ?MODULE, count_ignored).
50
+ count_ignored(lager_event).
51
52
flush() ->
53
- gen_event:call(lager_event, ?MODULE, flush).
54
+ flush(lager_event).
55
56
print_state() ->
57
- gen_event:call(lager_event, ?MODULE, print_state).
58
+ print_state(lager_event).
59
60
print_bad_state() ->
61
- gen_event:call(lager_event, ?MODULE, print_bad_state).
62
+ print_bad_state(lager_event).
63
+
64
+pop(Sink) ->
65
+ gen_event:call(Sink, ?MODULE, pop).
66
+
67
+count(Sink) ->
68
+ gen_event:call(Sink, ?MODULE, count).
69
+
70
+count_ignored(Sink) ->
71
+ gen_event:call(Sink, ?MODULE, count_ignored).
72
+
73
+flush(Sink) ->
74
+ gen_event:call(Sink, ?MODULE, flush).
75
+
76
+print_state(Sink) ->
77
+ gen_event:call(Sink, ?MODULE, print_state).
78
+
79
+print_bad_state(Sink) ->
80
+ gen_event:call(Sink, ?MODULE, print_bad_state).
81
+
82
83
has_line_numbers() ->
84
%% are we R15 or greater
85
- Rel = erlang:system_info(otp_release),
86
- {match, [Major]} = re:run(Rel, "(?|(^R(\\d+)[A|B](|0(\\d)))|(^(\\d+)$))", [{capture, [2], list}]),
87
- list_to_integer(Major) >= 15.
88
+ % this gets called a LOT - cache the answer
89
+ case erlang:get({?MODULE, has_line_numbers}) of
90
+ undefined ->
91
+ R = otp_version() >= 15,
92
+ erlang:put({?MODULE, has_line_numbers}, R),
93
+ R;
94
+ Bool ->
95
+ Bool
96
+ end.
97
+
98
+otp_version() ->
99
+ otp_version(erlang:system_info(otp_release)).
100
+
101
+otp_version([$R | Rel]) ->
102
+ {Ver, _} = string:to_integer(Rel),
103
+ Ver;
104
+otp_version(Rel) ->
105
+ {Ver, _} = string:to_integer(Rel),
106
+ Ver.
107
108
not_running_test() ->
109
?assertEqual({error, lager_not_running}, lager:log(info, self(), "not running")).
110
111
?assertEqual(0, count())
112
end
113
},
114
+ {"test sink not running",
115
+ fun() ->
116
+ ?assertEqual({error, {sink_not_configured, test}}, lager:log(test, info, self(), "~p", "not running"))
117
+ end
118
+ },
119
{"logging works",
120
fun() ->
121
lager:warning("test message"),
122
123
ok
124
end
125
},
126
+ {"unsafe logging works",
127
+ fun() ->
128
+ lager:warning_unsafe("test message"),
129
+ ?assertEqual(1, count()),
130
+ {Level, _Time, Message, _Metadata} = pop(),
131
+ ?assertMatch(Level, lager_util:level_to_num(warning)),
132
+ ?assertEqual("test message", Message),
133
+ ok
134
+ end
135
+ },
136
{"logging with arguments works",
137
fun() ->
138
lager:warning("test message ~p", [self()]),
139
140
ok
141
end
142
},
143
+ {"unsafe logging with args works",
144
+ fun() ->
145
+ lager:warning("test message ~p", [self()]),
146
+ ?assertEqual(1, count()),
147
+ {Level, _Time, Message,_Metadata} = pop(),
148
+ ?assertMatch(Level, lager_util:level_to_num(warning)),
149
+ ?assertEqual(lists:flatten(io_lib:format("test message ~p", [self()])), lists:flatten(Message)),
150
+ ok
151
+ end
152
+ },
153
{"logging works from inside a begin/end block",
154
fun() ->
155
?assertEqual(0, count()),
156
157
ok
158
end
159
},
160
+ {"stopped trace stops and removes its event handler - default sink (gh#267)",
161
+ fun() ->
162
+ Sink = ?DEFAULT_SINK,
163
+ StartHandlers = gen_event:which_handlers(Sink),
164
+ {_, T0} = lager_config:get({Sink, loglevel}),
165
+ StartGlobal = lager_config:global_get(handlers),
166
+ ?assertEqual([], T0),
167
+ {ok, TestTrace1} = lager:trace_file("/tmp/test", [{a,b}]),
168
+ MidHandlers = gen_event:which_handlers(Sink),
169
+ {ok, TestTrace2} = lager:trace_file("/tmp/test", [{c,d}]),
170
+ MidHandlers = gen_event:which_handlers(Sink),
171
+ ?assertEqual(length(StartHandlers)+1, length(MidHandlers)),
172
+ MidGlobal = lager_config:global_get(handlers),
173
+ ?assertEqual(length(StartGlobal)+1, length(MidGlobal)),
174
+ {_, T1} = lager_config:get({Sink, loglevel}),
175
+ ?assertEqual(2, length(T1)),
176
+ ok = lager:stop_trace(TestTrace1),
177
+ {_, T2} = lager_config:get({Sink, loglevel}),
178
+ ?assertEqual(1, length(T2)),
179
+ ?assertEqual(length(StartHandlers)+1, length(
180
+ gen_event:which_handlers(Sink))),
181
+
182
+ ?assertEqual(length(StartGlobal)+1, length(lager_config:global_get(handlers))),
183
+ ok = lager:stop_trace(TestTrace2),
184
+ EndHandlers = gen_event:which_handlers(?DEFAULT_SINK),
185
+ EndGlobal = lager_config:global_get(handlers),
186
+ {_, T3} = lager_config:get({Sink, loglevel}),
187
+ ?assertEqual([], T3),
188
+ ?assertEqual(StartHandlers, EndHandlers),
189
+ ?assertEqual(StartGlobal, EndGlobal),
190
+ ok
191
+ end
192
+ },
193
{"record printing works",
194
fun() ->
195
print_state(),
196
197
ok
198
end
199
},
200
+ {"unsafe messages really are not truncated",
201
+ fun() ->
202
+ lager:info_unsafe("doom, doom has come upon you all ~p", [string:copies("doom", 1500)]),
203
+ {_, _, Msg,_Metadata} = pop(),
204
+ ?assert(length(lists:flatten(Msg)) == 6035)
205
+ end
206
+ },
207
{"can't store invalid metadata",
208
fun() ->
209
?assertEqual(ok, lager:md([{platypus, gravid}, {sloth, hirsute}, {duck, erroneous}])),
210
211
]
212
}.
213
214
+extra_sinks_test_() ->
215
+ {foreach,
216
+ fun setup_sink/0,
217
+ fun cleanup/1,
218
+ [
219
+ {"observe that there is nothing up my sleeve",
220
+ fun() ->
221
+ ?assertEqual(undefined, pop(?TEST_SINK_EVENT)),
222
+ ?assertEqual(0, count(?TEST_SINK_EVENT))
223
+ end
224
+ },
225
+ {"logging works",
226
+ fun() ->
227
+ ?TEST_SINK_NAME:warning("test message"),
228
+ ?assertEqual(1, count(?TEST_SINK_EVENT)),
229
+ {Level, _Time, Message, _Metadata} = pop(?TEST_SINK_EVENT),
230
+ ?assertMatch(Level, lager_util:level_to_num(warning)),
231
+ ?assertEqual("test message", Message),
232
+ ok
233
+ end
234
+ },
235
+ {"logging with arguments works",
236
+ fun() ->
237
+ ?TEST_SINK_NAME:warning("test message ~p", [self()]),
238
+ ?assertEqual(1, count(?TEST_SINK_EVENT)),
239
+ {Level, _Time, Message,_Metadata} = pop(?TEST_SINK_EVENT),
240
+ ?assertMatch(Level, lager_util:level_to_num(warning)),
241
+ ?assertEqual(lists:flatten(io_lib:format("test message ~p", [self()])), lists:flatten(Message)),
242
+ ok
243
+ end
244
+ },
245
+ {"variables inplace of literals in logging statements work",
246
+ fun() ->
247
+ ?assertEqual(0, count(?TEST_SINK_EVENT)),
248
+ Attr = [{a, alpha}, {b, beta}],
249
+ Fmt = "format ~p",
250
+ Args = [world],
251
+ ?TEST_SINK_NAME:info(Attr, "hello"),
252
+ ?TEST_SINK_NAME:info(Attr, "hello ~p", [world]),
253
+ ?TEST_SINK_NAME:info(Fmt, [world]),
254
+ ?TEST_SINK_NAME:info("hello ~p", Args),
255
+ ?TEST_SINK_NAME:info(Attr, "hello ~p", Args),
256
+ ?TEST_SINK_NAME:info([{d, delta}, {g, gamma}], Fmt, Args),
257
+ ?assertEqual(6, count(?TEST_SINK_EVENT)),
258
+ {_Level, _Time, Message, Metadata} = pop(?TEST_SINK_EVENT),
259
+ ?assertMatch([{a, alpha}, {b, beta}|_], Metadata),
260
+ ?assertEqual("hello", lists:flatten(Message)),
261
+ {_Level, _Time2, Message2, _Metadata2} = pop(?TEST_SINK_EVENT),
262
+ ?assertEqual("hello world", lists:flatten(Message2)),
263
+ {_Level, _Time3, Message3, _Metadata3} = pop(?TEST_SINK_EVENT),
264
+ ?assertEqual("format world", lists:flatten(Message3)),
265
+ {_Level, _Time4, Message4, _Metadata4} = pop(?TEST_SINK_EVENT),
266
+ ?assertEqual("hello world", lists:flatten(Message4)),
267
+ {_Level, _Time5, Message5, _Metadata5} = pop(?TEST_SINK_EVENT),
268
+ ?assertEqual("hello world", lists:flatten(Message5)),
269
+ {_Level, _Time6, Message6, Metadata6} = pop(?TEST_SINK_EVENT),
270
+ ?assertMatch([{d, delta}, {g, gamma}|_], Metadata6),
271
+ ?assertEqual("format world", lists:flatten(Message6)),
272
+ ok
273
+ end
274
+ },
275
+ {"stopped trace stops and removes its event handler - test sink (gh#267)",
276
+ fun() ->
277
+ Sink = ?TEST_SINK_EVENT,
278
+ StartHandlers = gen_event:which_handlers(Sink),
279
+ {_, T0} = lager_config:get({Sink, loglevel}),
280
+ StartGlobal = lager_config:global_get(handlers),
281
+ ?assertEqual([], T0),
282
+ {ok, TestTrace1} = lager:trace_file("/tmp/test", [{sink, Sink}, {a,b}]),
283
+ MidHandlers = gen_event:which_handlers(Sink),
284
+ {ok, TestTrace2} = lager:trace_file("/tmp/test", [{sink, Sink}, {c,d}]),
285
+ MidHandlers = gen_event:which_handlers(Sink),
286
+ ?assertEqual(length(StartHandlers)+1, length(MidHandlers)),
287
+ MidGlobal = lager_config:global_get(handlers),
288
+ ?assertEqual(length(StartGlobal)+1, length(MidGlobal)),
289
+ {_, T1} = lager_config:get({Sink, loglevel}),
290
+ ?assertEqual(2, length(T1)),
291
+ ok = lager:stop_trace(TestTrace1),
292
+ {_, T2} = lager_config:get({Sink, loglevel}),
293
+ ?assertEqual(1, length(T2)),
294
+ ?assertEqual(length(StartHandlers)+1, length(
295
+ gen_event:which_handlers(Sink))),
296
+
297
+ ?assertEqual(length(StartGlobal)+1, length(lager_config:global_get(handlers))),
298
+ ok = lager:stop_trace(TestTrace2),
299
+ EndHandlers = gen_event:which_handlers(Sink),
300
+ EndGlobal = lager_config:global_get(handlers),
301
+ {_, T3} = lager_config:get({Sink, loglevel}),
302
+ ?assertEqual([], T3),
303
+ ?assertEqual(StartHandlers, EndHandlers),
304
+ ?assertEqual(StartGlobal, EndGlobal),
305
+ ok
306
+ end
307
+ },
308
+ {"log messages below the threshold are ignored",
309
+ fun() ->
310
+ ?assertEqual(0, count(?TEST_SINK_EVENT)),
311
+ ?TEST_SINK_NAME:debug("this message will be ignored"),
312
+ ?assertEqual(0, count(?TEST_SINK_EVENT)),
313
+ ?assertEqual(0, count_ignored(?TEST_SINK_EVENT)),
314
+ lager_config:set({?TEST_SINK_EVENT, loglevel}, {element(2, lager_util:config_to_mask(debug)), []}),
315
+ ?TEST_SINK_NAME:debug("this message should be ignored"),
316
+ ?assertEqual(0, count(?TEST_SINK_EVENT)),
317
+ ?assertEqual(1, count_ignored(?TEST_SINK_EVENT)),
318
+ lager:set_loglevel(?TEST_SINK_EVENT, ?MODULE, undefined, debug),
319
+ ?assertEqual({?DEBUG bor ?INFO bor ?NOTICE bor ?WARNING bor ?ERROR bor ?CRITICAL bor ?ALERT bor ?EMERGENCY, []}, lager_config:get({?TEST_SINK_EVENT, loglevel})),
320
+ ?TEST_SINK_NAME:debug("this message should be logged"),
321
+ ?assertEqual(1, count(?TEST_SINK_EVENT)),
322
+ ?assertEqual(1, count_ignored(?TEST_SINK_EVENT)),
323
+ ?assertEqual(debug, lager:get_loglevel(?TEST_SINK_EVENT, ?MODULE)),
324
+ ok
325
+ end
326
+ }
327
+ ]
328
+ }.
329
+
330
+setup_sink() ->
331
+ error_logger:tty(false),
332
+ application:load(lager),
333
+ application:set_env(lager, handlers, []),
334
+ application:set_env(lager, error_logger_redirect, false),
335
+ application:set_env(lager, extra_sinks, [{?TEST_SINK_EVENT, [{handlers, [{?MODULE, info}]}]}]),
336
+ lager:start(),
337
+ gen_event:call(lager_event, ?MODULE, flush),
338
+ gen_event:call(?TEST_SINK_EVENT, ?MODULE, flush).
339
+
340
setup() ->
341
error_logger:tty(false),
342
application:load(lager),
343
344
test_body(Expected, Actual) ->
345
case has_line_numbers() of
346
true ->
347
- FileLine = string:substr(Actual, length(Expected)+1),
348
- Body = string:substr(Actual, 1, length(Expected)),
349
+ ExLen = length(Expected),
350
+ {Body, Rest} = case length(Actual) > ExLen of
351
+ true ->
352
+ {string:substr(Actual, 1, ExLen),
353
+ string:substr(Actual, (ExLen + 1))};
354
+ _ ->
355
+ {Actual, []}
356
+ end,
357
?assertEqual(Expected, Body),
358
- case string:substr(FileLine, 1, 6) of
359
+ % OTP-17 (and maybe later releases) may tack on additional info
360
+ % about the failure, so if Actual starts with Expected (already
361
+ % confirmed by having gotten past assertEqual above) and ends
362
+ % with " line NNN" we can ignore what's in-between. By extension,
363
+ % since there may not be line information appended at all, any
364
+ % text we DO find is reportable, but not a test failure.
365
+ case Rest of
366
[] ->
367
- %% sometimes there's no line information...
368
- ?assert(true);
369
- " line " ->
370
- ?assert(true);
371
- Other ->
372
- ?debugFmt("unexpected trailing data ~p", [Other]),
373
- ?assert(false)
374
+ ok;
375
+ _ ->
376
+ % isolate the extra data and report it if it's not just
377
+ % a line number indicator
378
+ case re:run(Rest, "^.*( line \\d+)$", [{capture, [1]}]) of
379
+ nomatch ->
380
+ ?debugFmt(
381
+ "Trailing data \"~s\" following \"~s\"",
382
+ [Rest, Expected]);
383
+ {match, [{0, _}]} ->
384
+ % the whole sting is " line NNN"
385
+ ok;
386
+ {match, [{Off, _}]} ->
387
+ ?debugFmt(
388
+ "Trailing data \"~s\" following \"~s\"",
389
+ [string:substr(Rest, 1, Off), Expected])
390
+ end
391
end;
392
- false ->
393
+ _ ->
394
?assertEqual(Expected, Actual)
395
end.
396
397
+error_logger_redirect_crash_setup() ->
398
+ error_logger:tty(false),
399
+ application:load(lager),
400
+ application:set_env(lager, error_logger_redirect, true),
401
+ application:set_env(lager, handlers, [{?MODULE, error}]),
402
+ lager:start(),
403
+ crash:start(),
404
+ lager_event.
405
+
406
+error_logger_redirect_crash_setup_sink() ->
407
+ error_logger:tty(false),
408
+ application:load(lager),
409
+ application:set_env(lager, error_logger_redirect, true),
410
+ application:unset_env(lager, handlers),
411
+ application:set_env(lager, extra_sinks, [
412
+ {error_logger_lager_event, [
413
+ {handlers, [{?MODULE, error}]}]}]),
414
+ lager:start(),
415
+ crash:start(),
416
+ error_logger_lager_event.
417
+
418
+error_logger_redirect_crash_cleanup(_Sink) ->
419
+ application:stop(lager),
420
+ application:stop(goldrush),
421
+ application:unset_env(lager, extra_sinks),
422
+ case whereis(crash) of
423
+ undefined -> ok;
424
+ Pid -> exit(Pid, kill)
425
+ end,
426
+ error_logger:tty(true).
427
428
error_logger_redirect_crash_test_() ->
429
- TestBody=fun(Name,CrashReason,Expected) -> {Name,
430
+ TestBody=fun(Name,CrashReason,Expected) ->
431
+ fun(Sink) ->
432
+ {Name,
433
fun() ->
434
Pid = whereis(crash),
435
crash(CrashReason),
436
- {Level, _, Msg,Metadata} = pop(),
437
+ {Level, _, Msg,Metadata} = pop(Sink),
438
test_body(Expected, lists:flatten(Msg)),
439
?assertEqual(Pid,proplists:get_value(pid,Metadata)),
440
?assertEqual(lager_util:level_to_num(error),Level)
441
end
442
- }
443
+ }
444
+ end
445
end,
446
- {foreach,
447
- fun() ->
448
- error_logger:tty(false),
449
- application:load(lager),
450
- application:set_env(lager, error_logger_redirect, true),
451
- application:set_env(lager, handlers, [{?MODULE, error}]),
452
- lager:start(),
453
- crash:start()
454
- end,
455
-
456
- fun(_) ->
457
- application:stop(lager),
458
- application:stop(goldrush),
459
- case whereis(crash) of
460
- undefined -> ok;
461
- Pid -> exit(Pid, kill)
462
- end,
463
- error_logger:tty(true)
464
- end,
465
- [
466
+ Tests = [
467
+ fun(Sink) ->
468
{"again, there is nothing up my sleeve",
469
fun() ->
470
- ?assertEqual(undefined, pop()),
471
- ?assertEqual(0, count())
472
+ ?assertEqual(undefined, pop(Sink)),
473
+ ?assertEqual(0, count(Sink))
474
end
475
- },
476
+ }
477
+ end,
478
479
- TestBody("bad return value",bad_return,"gen_server crash terminated with reason: bad return value: bleh"),
480
- TestBody("bad return value with string",bad_return_string,"gen_server crash terminated with reason: bad return value: {tuple,{tuple,\"string\"}}"),
481
- TestBody("bad return uncaught throw",throw,"gen_server crash terminated with reason: bad return value: a_ball"),
482
- TestBody("case clause",case_clause,"gen_server crash terminated with reason: no case clause matching {} in crash:handle_call/3"),
483
- TestBody("case clause string",case_clause_string,"gen_server crash terminated with reason: no case clause matching \"crash\" in crash:handle_call/3"),
484
- TestBody("function clause",function_clause,"gen_server crash terminated with reason: no function clause matching crash:function({})"),
485
- TestBody("if clause",if_clause,"gen_server crash terminated with reason: no true branch found while evaluating if expression in crash:handle_call/3"),
486
- TestBody("try clause",try_clause,"gen_server crash terminated with reason: no try clause matching [] in crash:handle_call/3"),
487
- TestBody("undefined function",undef,"gen_server crash terminated with reason: call to undefined function crash:booger/0 from crash:handle_call/3"),
488
- TestBody("bad math",badarith,"gen_server crash terminated with reason: bad arithmetic expression in crash:handle_call/3"),
489
- TestBody("bad match",badmatch,"gen_server crash terminated with reason: no match of right hand value {} in crash:handle_call/3"),
490
- TestBody("bad arity",badarity,"gen_server crash terminated with reason: fun called with wrong arity of 1 instead of 3 in crash:handle_call/3"),
491
- TestBody("bad arg1",badarg1,"gen_server crash terminated with reason: bad argument in crash:handle_call/3"),
492
- 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"),
493
- TestBody("bad record",badrecord,"gen_server crash terminated with reason: bad record state in crash:handle_call/3"),
494
- TestBody("noproc",noproc,"gen_server crash terminated with reason: no such process or port in call to gen_event:call(foo, bar, baz)"),
495
- TestBody("badfun",badfun,"gen_server crash terminated with reason: bad function booger in crash:handle_call/3")
496
- ]
497
- }.
498
+ TestBody("bad return value",bad_return,"gen_server crash terminated with reason: bad return value: bleh"),
499
+ TestBody("bad return value with string",bad_return_string,"gen_server crash terminated with reason: bad return value: {tuple,{tuple,\"string\"}}"),
500
+ TestBody("bad return uncaught throw",throw,"gen_server crash terminated with reason: bad return value: a_ball"),
501
+ TestBody("case clause",case_clause,"gen_server crash terminated with reason: no case clause matching {} in crash:handle_call/3"),
502
+ TestBody("case clause string",case_clause_string,"gen_server crash terminated with reason: no case clause matching \"crash\" in crash:handle_call/3"),
503
+ TestBody("function clause",function_clause,"gen_server crash terminated with reason: no function clause matching crash:function({})"),
504
+ TestBody("if clause",if_clause,"gen_server crash terminated with reason: no true branch found while evaluating if expression in crash:handle_call/3"),
505
+ TestBody("try clause",try_clause,"gen_server crash terminated with reason: no try clause matching [] in crash:handle_call/3"),
506
+ TestBody("undefined function",undef,"gen_server crash terminated with reason: call to undefined function crash:booger/0 from crash:handle_call/3"),
507
+ TestBody("bad math",badarith,"gen_server crash terminated with reason: bad arithmetic expression in crash:handle_call/3"),
508
+ TestBody("bad match",badmatch,"gen_server crash terminated with reason: no match of right hand value {} in crash:handle_call/3"),
509
+ TestBody("bad arity",badarity,"gen_server crash terminated with reason: fun called with wrong arity of 1 instead of 3 in crash:handle_call/3"),
510
+ TestBody("bad arg1",badarg1,"gen_server crash terminated with reason: bad argument in crash:handle_call/3"),
511
+ 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"),
512
+ TestBody("bad record",badrecord,"gen_server crash terminated with reason: bad record state in crash:handle_call/3"),
513
+ TestBody("noproc",noproc,"gen_server crash terminated with reason: no such process or port in call to gen_event:call(foo, bar, baz)"),
514
+ TestBody("badfun",badfun,"gen_server crash terminated with reason: bad function booger in crash:handle_call/3")
515
+ ],
516
+ {"Error logger redirect crash", [
517
+ {"Redirect to default sink",
518
+ {foreach,
519
+ fun error_logger_redirect_crash_setup/0,
520
+ fun error_logger_redirect_crash_cleanup/1,
521
+ Tests}},
522
+ {"Redirect to error_logger_lager_event sink",
523
+ {foreach,
524
+ fun error_logger_redirect_crash_setup_sink/0,
525
+ fun error_logger_redirect_crash_cleanup/1,
526
+ Tests}}
527
+ ]}.
528
529
-error_logger_redirect_test_() ->
530
- {foreach,
531
- fun() ->
532
- error_logger:tty(false),
533
- application:load(lager),
534
- application:set_env(lager, error_logger_redirect, true),
535
- application:set_env(lager, handlers, [{?MODULE, info}]),
536
- lager:start(),
537
- lager:log(error, self(), "flush flush"),
538
- timer:sleep(100),
539
- gen_event:call(lager_event, ?MODULE, flush)
540
- end,
541
542
- fun(_) ->
543
- application:stop(lager),
544
- application:stop(goldrush),
545
- error_logger:tty(true)
546
- end,
547
- [
548
+error_logger_redirect_setup() ->
549
+ error_logger:tty(false),
550
+ application:load(lager),
551
+ application:set_env(lager, error_logger_redirect, true),
552
+ application:set_env(lager, handlers, [{?MODULE, info}]),
553
+ lager:start(),
554
+ lager:log(error, self(), "flush flush"),
555
+ timer:sleep(100),
556
+ gen_event:call(lager_event, ?MODULE, flush),
557
+ lager_event.
558
+
559
+error_logger_redirect_setup_sink() ->
560
+ error_logger:tty(false),
561
+ application:load(lager),
562
+ application:set_env(lager, error_logger_redirect, true),
563
+ application:unset_env(lager, handlers),
564
+ application:set_env(lager, extra_sinks, [
565
+ {error_logger_lager_event, [
566
+ {handlers, [{?MODULE, info}]}]}]),
567
+ lager:start(),
568
+ lager:log(error_logger_lager_event, error, self(), "flush flush", []),
569
+ timer:sleep(100),
570
+ gen_event:call(error_logger_lager_event, ?MODULE, flush),
571
+ error_logger_lager_event.
572
+
573
+error_logger_redirect_cleanup(_) ->
574
+ application:stop(lager),
575
+ application:stop(goldrush),
576
+ application:unset_env(lager, extra_sinks),
577
+ error_logger:tty(true).
578
+
579
+error_logger_redirect_test_() ->
580
+ Tests = [
581
{"error reports are printed",
582
- fun() ->
583
+ fun(Sink) ->
584
sync_error_logger:error_report([{this, is}, a, {silly, format}]),
585
_ = gen_event:which_handlers(error_logger),
586
- {Level, _, Msg,Metadata} = pop(),
587
+ {Level, _, Msg,Metadata} = pop(Sink),
588
?assertEqual(lager_util:level_to_num(error),Level),
589
?assertEqual(self(),proplists:get_value(pid,Metadata)),
590
Expected = "this: is, a, silly: format",
591
592
end
593
},
594
{"string error reports are printed",
595
- fun() ->
596
+ fun(Sink) ->
597
sync_error_logger:error_report("this is less silly"),
598
_ = gen_event:which_handlers(error_logger),
599
- {Level, _, Msg,Metadata} = pop(),
600
+ {Level, _, Msg,Metadata} = pop(Sink),
601
?assertEqual(lager_util:level_to_num(error),Level),
602
?assertEqual(self(),proplists:get_value(pid,Metadata)),
603
Expected = "this is less silly",
604
605
end
606
},
607
{"error messages are printed",
608
- fun() ->
609
+ fun(Sink) ->
610
sync_error_logger:error_msg("doom, doom has come upon you all"),
611
_ = gen_event:which_handlers(error_logger),
612
- {Level, _, Msg,Metadata} = pop(),
613
+ {Level, _, Msg,Metadata} = pop(Sink),
614
?assertEqual(lager_util:level_to_num(error),Level),
615
?assertEqual(self(),proplists:get_value(pid,Metadata)),
616
Expected = "doom, doom has come upon you all",
617
?assertEqual(Expected, lists:flatten(Msg))
618
end
619
},
620
+ {"error messages with unicode characters in Args are printed",
621
+ fun(Sink) ->
622
+ sync_error_logger:error_msg("~ts", ["Привет!"]),
623
+ _ = gen_event:which_handlers(error_logger),
624
+ {Level, _, Msg,Metadata} = pop(Sink),
625
+ ?assertEqual(lager_util:level_to_num(error),Level),
626
+ ?assertEqual(self(),proplists:get_value(pid,Metadata)),
627
+ ?assertEqual("Привет!", lists:flatten(Msg))
628
+ end
629
+ },
630
{"error messages are truncated at 4096 characters",
631
- fun() ->
632
+ fun(Sink) ->
633
sync_error_logger:error_msg("doom, doom has come upon you all ~p", [string:copies("doom", 10000)]),
634
_ = gen_event:which_handlers(error_logger),
635
- {_, _, Msg,_Metadata} = pop(),
636
+ {_, _, Msg,_Metadata} = pop(Sink),
637
?assert(length(lists:flatten(Msg)) < 5100)
638
end
639
},
640
+
641
{"info reports are printed",
642
- fun() ->
643
+ fun(Sink) ->
644
sync_error_logger:info_report([{this, is}, a, {silly, format}]),
645
_ = gen_event:which_handlers(error_logger),
646
- {Level, _, Msg,Metadata} = pop(),
647
+ {Level, _, Msg,Metadata} = pop(Sink),
648
?assertEqual(lager_util:level_to_num(info),Level),
649
?assertEqual(self(),proplists:get_value(pid,Metadata)),
650
Expected = "this: is, a, silly: format",
651
652
end
653
},
654
{"info reports are truncated at 4096 characters",
655
- fun() ->
656
+ fun(Sink) ->
657
sync_error_logger:info_report([[{this, is}, a, {silly, format}] || _ <- lists:seq(0, 600)]),
658
_ = gen_event:which_handlers(error_logger),
659
- {Level, _, Msg,Metadata} = pop(),
660
+ {Level, _, Msg,Metadata} = pop(Sink),
661
?assertEqual(lager_util:level_to_num(info),Level),
662
?assertEqual(self(),proplists:get_value(pid,Metadata)),
663
?assert(length(lists:flatten(Msg)) < 5000)
664
end
665
},
666
{"single term info reports are printed",
667
- fun() ->
668
+ fun(Sink) ->
669
sync_error_logger:info_report({foolish, bees}),
670
_ = gen_event:which_handlers(error_logger),
671
- {Level, _, Msg,Metadata} = pop(),
672
+ {Level, _, Msg,Metadata} = pop(Sink),
673
?assertEqual(lager_util:level_to_num(info),Level),
674
?assertEqual(self(),proplists:get_value(pid,Metadata)),
675
?assertEqual("{foolish,bees}", lists:flatten(Msg))
676
end
677
},
678
{"single term error reports are printed",
679
- fun() ->
680
+ fun(Sink) ->
681
sync_error_logger:error_report({foolish, bees}),
682
_ = gen_event:which_handlers(error_logger),
683
- {Level, _, Msg,Metadata} = pop(),
684
+ {Level, _, Msg,Metadata} = pop(Sink),
685
?assertEqual(lager_util:level_to_num(error),Level),
686
?assertEqual(self(),proplists:get_value(pid,Metadata)),
687
?assertEqual("{foolish,bees}", lists:flatten(Msg))
688
end
689
},
690
{"string info reports are printed",
691
- fun() ->
692
+ fun(Sink) ->
693
sync_error_logger:info_report("this is less silly"),
694
_ = gen_event:which_handlers(error_logger),
695
- {Level, _, Msg,Metadata} = pop(),
696
+ {Level, _, Msg,Metadata} = pop(Sink),
697
?assertEqual(lager_util:level_to_num(info),Level),
698
?assertEqual(self(),proplists:get_value(pid,Metadata)),
699
?assertEqual("this is less silly", lists:flatten(Msg))
700
end
701
},
702
{"string info reports are truncated at 4096 characters",
703
- fun() ->
704
+ fun(Sink) ->
705
sync_error_logger:info_report(string:copies("this is less silly", 1000)),
706
_ = gen_event:which_handlers(error_logger),
707
- {Level, _, Msg,Metadata} = pop(),
708
+ {Level, _, Msg,Metadata} = pop(Sink),
709
?assertEqual(lager_util:level_to_num(info),Level),
710
?assertEqual(self(),proplists:get_value(pid,Metadata)),
711
?assert(length(lists:flatten(Msg)) < 5100)
712
end
713
},
714
{"strings in a mixed report are printed as strings",
715
- fun() ->
716
+ fun(Sink) ->
717
sync_error_logger:info_report(["this is less silly", {than, "this"}]),
718
_ = gen_event:which_handlers(error_logger),
719
- {Level, _, Msg,Metadata} = pop(),
720
+ {Level, _, Msg,Metadata} = pop(Sink),
721
?assertEqual(lager_util:level_to_num(info),Level),
722
?assertEqual(self(),proplists:get_value(pid,Metadata)),
723
?assertEqual("\"this is less silly\", than: \"this\"", lists:flatten(Msg))
724
end
725
},
726
{"info messages are printed",
727
- fun() ->
728
+ fun(Sink) ->
729
sync_error_logger:info_msg("doom, doom has come upon you all"),
730
_ = gen_event:which_handlers(error_logger),
731
- {Level, _, Msg,Metadata} = pop(),
732
+ {Level, _, Msg,Metadata} = pop(Sink),
733
?assertEqual(lager_util:level_to_num(info),Level),
734
?assertEqual(self(),proplists:get_value(pid,Metadata)),
735
?assertEqual("doom, doom has come upon you all", lists:flatten(Msg))
736
end
737
},
738
{"info messages are truncated at 4096 characters",
739
- fun() ->
740
+ fun(Sink) ->
741
sync_error_logger:info_msg("doom, doom has come upon you all ~p", [string:copies("doom", 10000)]),
742
_ = gen_event:which_handlers(error_logger),
743
- {Level, _, Msg,Metadata} = pop(),
744
+ {Level, _, Msg,Metadata} = pop(Sink),
745
?assertEqual(lager_util:level_to_num(info),Level),
746
?assertEqual(self(),proplists:get_value(pid,Metadata)),
747
?assert(length(lists:flatten(Msg)) < 5100)
748
end
749
},
750
+ {"info messages with unicode characters in Args are printed",
751
+ fun(Sink) ->
752
+ sync_error_logger:info_msg("~ts", ["Привет!"]),
753
+ _ = gen_event:which_handlers(error_logger),
754
+ {Level, _, Msg,Metadata} = pop(Sink),
755
+ ?assertEqual(lager_util:level_to_num(info),Level),
756
+ ?assertEqual(self(),proplists:get_value(pid,Metadata)),
757
+ ?assertEqual("Привет!", lists:flatten(Msg))
758
+ end
759
+ },
760
+ {"warning messages with unicode characters in Args are printed",
761
+ fun(Sink) ->
762
+ sync_error_logger:warning_msg("~ts", ["Привет!"]),
763
+ Map = error_logger:warning_map(),
764
+ _ = gen_event:which_handlers(error_logger),
765
+ {Level, _, Msg,Metadata} = pop(Sink),
766
+ ?assertEqual(lager_util:level_to_num(Map),Level),
767
+ ?assertEqual(self(),proplists:get_value(pid,Metadata)),
768
+ ?assertEqual("Привет!", lists:flatten(Msg))
769
+ end
770
+ },
771
772
{"warning messages are printed at the correct level",
773
- fun() ->
774
+ fun(Sink) ->
775
sync_error_logger:warning_msg("doom, doom has come upon you all"),
776
Map = error_logger:warning_map(),
777
_ = gen_event:which_handlers(error_logger),
778
- {Level, _, Msg,Metadata} = pop(),
779
+ {Level, _, Msg,Metadata} = pop(Sink),
780
?assertEqual(lager_util:level_to_num(Map),Level),
781
?assertEqual(self(),proplists:get_value(pid,Metadata)),
782
?assertEqual("doom, doom has come upon you all", lists:flatten(Msg))
783
end
784
},
785
{"warning reports are printed at the correct level",
786
- fun() ->
787
+ fun(Sink) ->
788
sync_error_logger:warning_report([{i, like}, pie]),
789
Map = error_logger:warning_map(),
790
_ = gen_event:which_handlers(error_logger),
791
- {Level, _, Msg,Metadata} = pop(),
792
+ {Level, _, Msg,Metadata} = pop(Sink),
793
?assertEqual(lager_util:level_to_num(Map),Level),
794
?assertEqual(self(),proplists:get_value(pid,Metadata)),
795
?assertEqual("i: like, pie", lists:flatten(Msg))
796
end
797
},
798
{"single term warning reports are printed at the correct level",
799
- fun() ->
800
+ fun(Sink) ->
801
sync_error_logger:warning_report({foolish, bees}),
802
Map = error_logger:warning_map(),
803
_ = gen_event:which_handlers(error_logger),
804
- {Level, _, Msg,Metadata} = pop(),
805
+ {Level, _, Msg,Metadata} = pop(Sink),
806
?assertEqual(lager_util:level_to_num(Map),Level),
807
?assertEqual(self(),proplists:get_value(pid,Metadata)),
808
?assertEqual("{foolish,bees}", lists:flatten(Msg))
809
end
810
},
811
{"application stop reports",
812
- fun() ->
813
+ fun(Sink) ->
814
sync_error_logger:info_report([{application, foo}, {exited, quittin_time}, {type, lazy}]),
815
_ = gen_event:which_handlers(error_logger),
816
- {Level, _, Msg,Metadata} = pop(),
817
+ {Level, _, Msg,Metadata} = pop(Sink),
818
?assertEqual(lager_util:level_to_num(info),Level),
819
?assertEqual(self(),proplists:get_value(pid,Metadata)),
820
?assertEqual("Application foo exited with reason: quittin_time", lists:flatten(Msg))
821
end
822
},
823
{"supervisor reports",
824
- fun() ->
825
+ fun(Sink) ->
826
sync_error_logger:error_report(supervisor_report, [{errorContext, france}, {offender, [{name, mini_steve}, {mfargs, {a, b, [c]}}, {pid, bleh}]}, {reason, fired}, {supervisor, {local, steve}}]),
827
_ = gen_event:which_handlers(error_logger),
828
- {Level, _, Msg,Metadata} = pop(),
829
+ {Level, _, Msg,Metadata} = pop(Sink),
830
?assertEqual(lager_util:level_to_num(error),Level),
831
?assertEqual(self(),proplists:get_value(pid,Metadata)),
832
?assertEqual("Supervisor steve had child mini_steve started with a:b(c) at bleh exit with reason fired in context france", lists:flatten(Msg))
833
end
834
},
835
{"supervisor reports with real error",
836
- fun() ->
837
+ fun(Sink) ->
838
sync_error_logger:error_report(supervisor_report, [{errorContext, france}, {offender, [{name, mini_steve}, {mfargs, {a, b, [c]}}, {pid, bleh}]}, {reason, {function_clause,[{crash,handle_info,[foo]}]}}, {supervisor, {local, steve}}]),
839
_ = gen_event:which_handlers(error_logger),
840
- {Level, _, Msg,Metadata} = pop(),
841
+ {Level, _, Msg,Metadata} = pop(Sink),
842
?assertEqual(lager_util:level_to_num(error),Level),
843
?assertEqual(self(),proplists:get_value(pid,Metadata)),
844
?assertEqual("Supervisor steve had child mini_steve started with a:b(c) at bleh exit with reason no function clause matching crash:handle_info(foo) in context france", lists:flatten(Msg))
845
846
},
847
848
{"supervisor reports with real error and pid",
849
- fun() ->
850
+ fun(Sink) ->
851
sync_error_logger:error_report(supervisor_report, [{errorContext, france}, {offender, [{name, mini_steve}, {mfargs, {a, b, [c]}}, {pid, bleh}]}, {reason, {function_clause,[{crash,handle_info,[foo]}]}}, {supervisor, somepid}]),
852
_ = gen_event:which_handlers(error_logger),
853
- {Level, _, Msg,Metadata} = pop(),
854
+ {Level, _, Msg,Metadata} = pop(Sink),
855
?assertEqual(lager_util:level_to_num(error),Level),
856
?assertEqual(self(),proplists:get_value(pid,Metadata)),
857
?assertEqual("Supervisor somepid had child mini_steve started with a:b(c) at bleh exit with reason no function clause matching crash:handle_info(foo) in context france", lists:flatten(Msg))
858
859
},
860
861
{"supervisor_bridge reports",
862
- fun() ->
863
+ fun(Sink) ->
864
sync_error_logger:error_report(supervisor_report, [{errorContext, france}, {offender, [{mod, mini_steve}, {pid, bleh}]}, {reason, fired}, {supervisor, {local, steve}}]),
865
_ = gen_event:which_handlers(error_logger),
866
- {Level, _, Msg,Metadata} = pop(),
867
+ {Level, _, Msg,Metadata} = pop(Sink),
868
?assertEqual(lager_util:level_to_num(error),Level),
869
?assertEqual(self(),proplists:get_value(pid,Metadata)),
870
?assertEqual("Supervisor steve had child at module mini_steve at bleh exit with reason fired in context france", lists:flatten(Msg))
871
end
872
},
873
{"application progress report",
874
- fun() ->
875
+ fun(Sink) ->
876
sync_error_logger:info_report(progress, [{application, foo}, {started_at, node()}]),
877
_ = gen_event:which_handlers(error_logger),
878
- {Level, _, Msg,Metadata} = pop(),
879
+ {Level, _, Msg,Metadata} = pop(Sink),
880
?assertEqual(lager_util:level_to_num(info),Level),
881
?assertEqual(self(),proplists:get_value(pid,Metadata)),
882
Expected = lists:flatten(io_lib:format("Application foo started on node ~w", [node()])),
883
884
end
885
},
886
{"supervisor progress report",
887
- fun() ->
888
- lager:set_loglevel(?MODULE, debug),
889
- ?assertEqual({?DEBUG bor ?INFO bor ?NOTICE bor ?WARNING bor ?ERROR bor ?CRITICAL bor ?ALERT bor ?EMERGENCY, []}, lager_config:get(loglevel)),
890
+ fun(Sink) ->
891
+ lager:set_loglevel(Sink, ?MODULE, undefined, debug),
892
+ ?assertEqual({?DEBUG bor ?INFO bor ?NOTICE bor ?WARNING bor ?ERROR bor ?CRITICAL bor ?ALERT bor ?EMERGENCY, []}, lager_config:get({Sink, loglevel})),
893
sync_error_logger:info_report(progress, [{supervisor, {local, foo}}, {started, [{mfargs, {foo, bar, 1}}, {pid, baz}]}]),
894
_ = gen_event:which_handlers(error_logger),
895
- {Level, _, Msg,Metadata} = pop(),
896
+ {Level, _, Msg,Metadata} = pop(Sink),
897
?assertEqual(lager_util:level_to_num(debug),Level),
898
?assertEqual(self(),proplists:get_value(pid,Metadata)),
899
?assertEqual("Supervisor foo started foo:bar/1 at pid baz", lists:flatten(Msg))
900
end
901
},
902
{"supervisor progress report with pid",
903
- fun() ->
904
- lager:set_loglevel(?MODULE, debug),
905
- ?assertEqual({?DEBUG bor ?INFO bor ?NOTICE bor ?WARNING bor ?ERROR bor ?CRITICAL bor ?ALERT bor ?EMERGENCY, []}, lager_config:get(loglevel)),
906
+ fun(Sink) ->
907
+ lager:set_loglevel(Sink, ?MODULE, undefined, debug),
908
+ ?assertEqual({?DEBUG bor ?INFO bor ?NOTICE bor ?WARNING bor ?ERROR bor ?CRITICAL bor ?ALERT bor ?EMERGENCY, []}, lager_config:get({Sink, loglevel})),
909
sync_error_logger:info_report(progress, [{supervisor, somepid}, {started, [{mfargs, {foo, bar, 1}}, {pid, baz}]}]),
910
_ = gen_event:which_handlers(error_logger),
911
- {Level, _, Msg,Metadata} = pop(),
912
+ {Level, _, Msg,Metadata} = pop(Sink),
913
?assertEqual(lager_util:level_to_num(debug),Level),
914
?assertEqual(self(),proplists:get_value(pid,Metadata)),
915
?assertEqual("Supervisor somepid started foo:bar/1 at pid baz", lists:flatten(Msg))
916
end
917
},
918
{"crash report for emfile",
919
- fun() ->
920
+ fun(Sink) ->
921
sync_error_logger:error_report(crash_report, [[{pid, self()}, {registered_name, []}, {error_info, {error, emfile, [{stack, trace, 1}]}}], []]),
922
_ = gen_event:which_handlers(error_logger),
923
- {Level, _, Msg,Metadata} = pop(),
924
+ {Level, _, Msg,Metadata} = pop(Sink),
925
?assertEqual(lager_util:level_to_num(error),Level),
926
?assertEqual(self(),proplists:get_value(pid,Metadata)),
927
Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~w with 0 neighbours crashed with reason: maximum number of file descriptors exhausted, check ulimit -n", [self()])),
928
929
end
930
},
931
{"crash report for system process limit",
932
- fun() ->
933
+ fun(Sink) ->
934
sync_error_logger:error_report(crash_report, [[{pid, self()}, {registered_name, []}, {error_info, {error, system_limit, [{erlang, spawn, 1}]}}], []]),
935
_ = gen_event:which_handlers(error_logger),
936
- {Level, _, Msg,Metadata} = pop(),
937
+ {Level, _, Msg,Metadata} = pop(Sink),
938
?assertEqual(lager_util:level_to_num(error),Level),
939
?assertEqual(self(),proplists:get_value(pid,Metadata)),
940
Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~w with 0 neighbours crashed with reason: system limit: maximum number of processes exceeded", [self()])),
941
942
end
943
},
944
{"crash report for system process limit2",
945
- fun() ->
946
+ fun(Sink) ->
947
sync_error_logger:error_report(crash_report, [[{pid, self()}, {registered_name, []}, {error_info, {error, system_limit, [{erlang, spawn_opt, 1}]}}], []]),
948
_ = gen_event:which_handlers(error_logger),
949
- {Level, _, Msg,Metadata} = pop(),
950
+ {Level, _, Msg,Metadata} = pop(Sink),
951
?assertEqual(lager_util:level_to_num(error),Level),
952
?assertEqual(self(),proplists:get_value(pid,Metadata)),
953
Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~w with 0 neighbours crashed with reason: system limit: maximum number of processes exceeded", [self()])),
954
955
end
956
},
957
{"crash report for system port limit",
958
- fun() ->
959
+ fun(Sink) ->
960
sync_error_logger:error_report(crash_report, [[{pid, self()}, {registered_name, []}, {error_info, {error, system_limit, [{erlang, open_port, 1}]}}], []]),
961
_ = gen_event:which_handlers(error_logger),
962
- {Level, _, Msg,Metadata} = pop(),
963
+ {Level, _, Msg,Metadata} = pop(Sink),
964
?assertEqual(lager_util:level_to_num(error),Level),
965
?assertEqual(self(),proplists:get_value(pid,Metadata)),
966
Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~w with 0 neighbours crashed with reason: system limit: maximum number of ports exceeded", [self()])),
967
968
end
969
},
970
{"crash report for system port limit",
971
- fun() ->
972
+ fun(Sink) ->
973
sync_error_logger:error_report(crash_report, [[{pid, self()}, {registered_name, []}, {error_info, {error, system_limit, [{erlang, list_to_atom, 1}]}}], []]),
974
_ = gen_event:which_handlers(error_logger),
975
- {Level, _, Msg,Metadata} = pop(),
976
+ {Level, _, Msg,Metadata} = pop(Sink),
977
?assertEqual(lager_util:level_to_num(error),Level),
978
?assertEqual(self(),proplists:get_value(pid,Metadata)),
979
Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~w with 0 neighbours crashed with reason: system limit: tried to create an atom larger than 255, or maximum atom count exceeded", [self()])),
980
981
end
982
},
983
{"crash report for system ets table limit",
984
- fun() ->
985
+ fun(Sink) ->
986
sync_error_logger:error_report(crash_report, [[{pid, self()}, {registered_name, test}, {error_info, {error, system_limit, [{ets,new,[segment_offsets,[ordered_set,public]]},{mi_segment,open_write,1},{mi_buffer_converter,handle_cast,2},{gen_server,handle_msg,5},{proc_lib,init_p_do_apply,3}]}}], []]),
987
_ = gen_event:which_handlers(error_logger),
988
- {Level, _, Msg,Metadata} = pop(),
989
+ {Level, _, Msg,Metadata} = pop(Sink),
990
?assertEqual(lager_util:level_to_num(error),Level),
991
?assertEqual(self(),proplists:get_value(pid,Metadata)),
992
Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~w with 0 neighbours crashed with reason: system limit: maximum number of ETS tables exceeded", [test])),
993
994
end
995
},
996
{"crash report for unknown system limit should be truncated at 500 characters",
997
- fun() ->
998
+ fun(Sink) ->
999
sync_error_logger:error_report(crash_report, [[{pid, self()}, {error_info, {error, system_limit, [{wtf,boom,[string:copies("aaaa", 4096)]}]}}], []]),
1000
_ = gen_event:which_handlers(error_logger),
1001
- {_, _, Msg,_Metadata} = pop(),
1002
+ {_, _, Msg,_Metadata} = pop(Sink),
1003
?assert(length(lists:flatten(Msg)) > 550),
1004
?assert(length(lists:flatten(Msg)) < 600)
1005
end
1006
},
1007
- {"crash reports for 'special processes' should be handled right - function_clause",
1008
- fun() ->
1009
+ {"crash reports for 'special processes' should be handled right - function_clause",
1010
+ fun(Sink) ->
1011
{ok, Pid} = special_process:start(),
1012
unlink(Pid),
1013
Pid ! function_clause,
1014
timer:sleep(500),
1015
_ = gen_event:which_handlers(error_logger),
1016
- {_, _, Msg, _Metadata} = pop(),
1017
+ {_, _, Msg, _Metadata} = pop(Sink),
1018
Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~p with 0 neighbours crashed with reason: no function clause matching special_process:foo(bar)",
1019
[Pid])),
1020
test_body(Expected, lists:flatten(Msg))
1021
end
1022
},
1023
- {"crash reports for 'special processes' should be handled right - case_clause",
1024
- fun() ->
1025
+ {"crash reports for 'special processes' should be handled right - case_clause",
1026
+ fun(Sink) ->
1027
{ok, Pid} = special_process:start(),
1028
unlink(Pid),
1029
Pid ! {case_clause, wtf},
1030
timer:sleep(500),
1031
_ = gen_event:which_handlers(error_logger),
1032
- {_, _, Msg, _Metadata} = pop(),
1033
+ {_, _, Msg, _Metadata} = pop(Sink),
1034
Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~p with 0 neighbours crashed with reason: no case clause matching wtf in special_process:loop/0",
1035
[Pid])),
1036
test_body(Expected, lists:flatten(Msg))
1037
end
1038
},
1039
- {"crash reports for 'special processes' should be handled right - exit",
1040
- fun() ->
1041
+ {"crash reports for 'special processes' should be handled right - exit",
1042
+ fun(Sink) ->
1043
{ok, Pid} = special_process:start(),
1044
unlink(Pid),
1045
Pid ! exit,
1046
timer:sleep(500),
1047
_ = gen_event:which_handlers(error_logger),
1048
- {_, _, Msg, _Metadata} = pop(),
1049
+ {_, _, Msg, _Metadata} = pop(Sink),
1050
Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~p with 0 neighbours exited with reason: byebye in special_process:loop/0",
1051
[Pid])),
1052
test_body(Expected, lists:flatten(Msg))
1053
end
1054
},
1055
- {"crash reports for 'special processes' should be handled right - error",
1056
- fun() ->
1057
+ {"crash reports for 'special processes' should be handled right - error",
1058
+ fun(Sink) ->
1059
{ok, Pid} = special_process:start(),
1060
unlink(Pid),
1061
Pid ! error,
1062
timer:sleep(500),
1063
_ = gen_event:which_handlers(error_logger),
1064
- {_, _, Msg, _Metadata} = pop(),
1065
+ {_, _, Msg, _Metadata} = pop(Sink),
1066
Expected = lists:flatten(io_lib:format("CRASH REPORT Process ~p with 0 neighbours crashed with reason: mybad in special_process:loop/0",
1067
[Pid])),
1068
test_body(Expected, lists:flatten(Msg))
1069
end
1070
},
1071
{"webmachine error reports",
1072
- fun() ->
1073
+ fun(Sink) ->
1074
Path = "/cgi-bin/phpmyadmin",
1075
Reason = {error,{error,{badmatch,{error,timeout}},
1076
[{myapp,dostuff,2,[{file,"src/myapp.erl"},{line,123}]},
1077
{webmachine_resource,resource_call,3,[{file,"src/webmachine_resource.erl"},{line,169}]}]}},
1078
sync_error_logger:error_msg("webmachine error: path=~p~n~p~n", [Path, Reason]),
1079
_ = gen_event:which_handlers(error_logger),
1080
- {Level, _, Msg,Metadata} = pop(),
1081
+ {Level, _, Msg,Metadata} = pop(Sink),
1082
?assertEqual(lager_util:level_to_num(error),Level),
1083
?assertEqual(self(),proplists:get_value(pid,Metadata)),
1084
?assertEqual("Webmachine error at path \"/cgi-bin/phpmyadmin\" : no match of right hand value {error,timeout} in myapp:dostuff/2 line 123", lists:flatten(Msg))
1085
1086
end
1087
},
1088
{"Cowboy error reports, 8 arg version",
1089
- fun() ->
1090
+ fun(Sink) ->
1091
Stack = [{my_handler,init, 3,[{file,"src/my_handler.erl"},{line,123}]},
1092
{cowboy_handler,handler_init,4,[{file,"src/cowboy_handler.erl"},{line,169}]}],
1093
1094
1095
[my_handler, init, 3, error, {badmatch, {error, timeout}}, [],
1096
"Request", Stack]),
1097
_ = gen_event:which_handlers(error_logger),
1098
- {Level, _, Msg,Metadata} = pop(),
1099
+ {Level, _, Msg,Metadata} = pop(Sink),
1100
?assertEqual(lager_util:level_to_num(error),Level),
1101
?assertEqual(self(),proplists:get_value(pid,Metadata)),
1102
?assertEqual("Cowboy handler my_handler terminated in my_handler:init/3 with reason: no match of right hand value {error,timeout} in my_handler:init/3 line 123", lists:flatten(Msg))
1103
end
1104
},
1105
{"Cowboy error reports, 10 arg version",
1106
- fun() ->
1107
+ fun(Sink) ->
1108
Stack = [{my_handler,somecallback, 3,[{file,"src/my_handler.erl"},{line,123}]},
1109
{cowboy_handler,handler_init,4,[{file,"src/cowboy_handler.erl"},{line,169}]}],
1110
sync_error_logger:error_msg(
1111
1112
{}, "Request", Stack]),
1113
1114
_ = gen_event:which_handlers(error_logger),
1115
- {Level, _, Msg,Metadata} = pop(),
1116
+ {Level, _, Msg,Metadata} = pop(Sink),
1117
?assertEqual(lager_util:level_to_num(error),Level),
1118
?assertEqual(self(),proplists:get_value(pid,Metadata)),
1119
?assertEqual("Cowboy handler my_handler terminated in my_handler:somecallback/3 with reason: no match of right hand value {error,timeout} in my_handler:somecallback/3 line 123", lists:flatten(Msg))
1120
end
1121
},
1122
{"Cowboy error reports, 5 arg version",
1123
- fun() ->
1124
+ fun(Sink) ->
1125
sync_error_logger:error_msg(
1126
"** Cowboy handler ~p terminating; "
1127
"function ~p/~p was not exported~n"
1128
"** Request was ~p~n** State was ~p~n~n",
1129
[my_handler, to_json, 2, "Request", {}]),
1130
_ = gen_event:which_handlers(error_logger),
1131
- {Level, _, Msg,Metadata} = pop(),
1132
+ {Level, _, Msg,Metadata} = pop(Sink),
1133
?assertEqual(lager_util:level_to_num(error),Level),
1134
?assertEqual(self(),proplists:get_value(pid,Metadata)),
1135
?assertEqual("Cowboy handler my_handler terminated with reason: call to undefined function my_handler:to_json/2", lists:flatten(Msg))
1136
end
1137
},
1138
{"messages should not be generated if they don't satisfy the threshold",
1139
- fun() ->
1140
- lager:set_loglevel(?MODULE, error),
1141
- ?assertEqual({?ERROR bor ?CRITICAL bor ?ALERT bor ?EMERGENCY, []}, lager_config:get(loglevel)),
1142
+ fun(Sink) ->
1143
+ lager:set_loglevel(Sink, ?MODULE, undefined, error),
1144
+ ?assertEqual({?ERROR bor ?CRITICAL bor ?ALERT bor ?EMERGENCY, []}, lager_config:get({Sink, loglevel})),
1145
sync_error_logger:info_report([hello, world]),
1146
_ = gen_event:which_handlers(error_logger),
1147
- ?assertEqual(0, count()),
1148
- ?assertEqual(0, count_ignored()),
1149
- lager:set_loglevel(?MODULE, info),
1150
- ?assertEqual({?INFO bor ?NOTICE bor ?WARNING bor ?ERROR bor ?CRITICAL bor ?ALERT bor ?EMERGENCY, []}, lager_config:get(loglevel)),
1151
+ ?assertEqual(0, count(Sink)),
1152
+ ?assertEqual(0, count_ignored(Sink)),
1153
+ lager:set_loglevel(Sink, ?MODULE, undefined, info),
1154
+ ?assertEqual({?INFO bor ?NOTICE bor ?WARNING bor ?ERROR bor ?CRITICAL bor ?ALERT bor ?EMERGENCY, []}, lager_config:get({Sink, loglevel})),
1155
sync_error_logger:info_report([hello, world]),
1156
_ = gen_event:which_handlers(error_logger),
1157
- ?assertEqual(1, count()),
1158
- ?assertEqual(0, count_ignored()),
1159
- lager:set_loglevel(?MODULE, error),
1160
- ?assertEqual({?ERROR bor ?CRITICAL bor ?ALERT bor ?EMERGENCY, []}, lager_config:get(loglevel)),
1161
- lager_config:set(loglevel, {element(2, lager_util:config_to_mask(debug)), []}),
1162
+ ?assertEqual(1, count(Sink)),
1163
+ ?assertEqual(0, count_ignored(Sink)),
1164
+ lager:set_loglevel(Sink, ?MODULE, undefined, error),
1165
+ ?assertEqual({?ERROR bor ?CRITICAL bor ?ALERT bor ?EMERGENCY, []}, lager_config:get({Sink, loglevel})),
1166
+ lager_config:set({Sink, loglevel}, {element(2, lager_util:config_to_mask(debug)), []}),
1167
sync_error_logger:info_report([hello, world]),
1168
_ = gen_event:which_handlers(error_logger),
1169
- ?assertEqual(1, count()),
1170
- ?assertEqual(1, count_ignored())
1171
+ ?assertEqual(1, count(Sink)),
1172
+ ?assertEqual(1, count_ignored(Sink))
1173
end
1174
}
1175
- ]
1176
- }.
1177
+ ],
1178
+ SinkTests = lists:map(
1179
+ fun({Name, F}) ->
1180
+ fun(Sink) -> {Name, fun() -> F(Sink) end} end
1181
+ end,
1182
+ Tests),
1183
+ {"Error logger redirect", [
1184
+ {"Redirect to default sink",
1185
+ {foreach,
1186
+ fun error_logger_redirect_setup/0,
1187
+ fun error_logger_redirect_cleanup/1,
1188
+ SinkTests}},
1189
+ {"Redirect to error_logger_lager_event sink",
1190
+ {foreach,
1191
+ fun error_logger_redirect_setup_sink/0,
1192
+ fun error_logger_redirect_cleanup/1,
1193
+ SinkTests}}
1194
+ ]}.
1195
1196
safe_format_test() ->
1197
?assertEqual("foo bar", lists:flatten(lager:safe_format("~p ~p", [foo, bar], 1024))),
1198
?assertEqual("FORMAT ERROR: \"~p ~p ~p\" [foo,bar]", lists:flatten(lager:safe_format("~p ~p ~p", [foo, bar], 1024))),
1199
ok.
1200
1201
+unsafe_format_test() ->
1202
+ ?assertEqual("foo bar", lists:flatten(lager:unsafe_format("~p ~p", [foo, bar]))),
1203
+ ?assertEqual("FORMAT ERROR: \"~p ~p ~p\" [foo,bar]", lists:flatten(lager:unsafe_format("~p ~p ~p", [foo, bar]))),
1204
+ ok.
1205
+
1206
async_threshold_test_() ->
1207
{foreach,
1208
fun() ->
1209
error_logger:tty(false),
1210
+ ets:new(async_threshold_test, [set, named_table, public]),
1211
+ ets:insert_new(async_threshold_test, {sync_toggled, 0}),
1212
+ ets:insert_new(async_threshold_test, {async_toggled, 0}),
1213
application:load(lager),
1214
application:set_env(lager, error_logger_redirect, false),
1215
application:set_env(lager, async_threshold, 2),
1216
1217
application:unset_env(lager, async_threshold),
1218
application:stop(lager),
1219
application:stop(goldrush),
1220
+ ets:delete(async_threshold_test),
1221
error_logger:tty(true)
1222
end,
1223
[
1224
1225
%% serialize on mailbox
1226
_ = gen_event:which_handlers(lager_event),
1227
timer:sleep(500),
1228
- %% there should be a ton of outstanding messages now, so async is false
1229
- ?assertEqual(false, lager_config:get(async)),
1230
- %% wait for all the workers to return, meaning that all the messages have been logged (since we're in sync mode)
1231
+
1232
+ %% By now the flood of messages will have
1233
+ %% forced the backend throttle to turn off
1234
+ %% async mode, but it's possible all
1235
+ %% outstanding requests have been processed,
1236
+ %% so checking the current status (sync or
1237
+ %% async) is an exercise in race control.
1238
+
1239
+ %% Instead, we'll see whether the backend
1240
+ %% throttle has toggled into sync mode at any
1241
+ %% point in the past
1242
+ ?assertMatch([{sync_toggled, N}] when N > 0,
1243
+ ets:lookup(async_threshold_test, sync_toggled)),
1244
+ %% wait for all the workers to return, meaning that all the messages have been logged (since we're definitely in sync mode at the end of the run)
1245
collect_workers(Workers),
1246
- %% serialize ont the mailbox again
1247
+ %% serialize on the mailbox again
1248
_ = gen_event:which_handlers(lager_event),
1249
%% just in case...
1250
timer:sleep(1000),
1251
1252
}.
1253
1254
-endif.
1255
-
1256
-
1257
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
17
1
2
3
-compile([{parse_transform, lager_transform}]).
4
5
--record(a, {field1, field2}).
6
--record(b, {field1, field2}).
7
+-record(a, {field1 :: term(), field2 :: term()}).
8
+-record(b, {field1 :: term() , field2 :: term()}).
9
10
11
--ifdef(TEST).
12
-include_lib("eunit/include/eunit.hrl").
13
--endif.
14
15
nested_record_test() ->
16
A = #a{field1 = x, field2 = y},
17
lager-3.1.0.tar.gz/test/pr_stacktrace_test.erl
Added
58
1
2
+-module(pr_stacktrace_test).
3
+
4
+-compile([{parse_transform, lager_transform}]).
5
+
6
+-include_lib("eunit/include/eunit.hrl").
7
+
8
+make_throw() ->
9
+ throw({test, exception}).
10
+
11
+bad_arity() ->
12
+ lists:concat([], []).
13
+
14
+bad_arg() ->
15
+ integer_to_list(1.0).
16
+
17
+pr_stacktrace_throw_test() ->
18
+ Result = try
19
+ make_throw()
20
+ catch
21
+ Class:Reason ->
22
+ lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason})
23
+ end,
24
+ExpectedPart = "
25
+ pr_stacktrace_test:pr_stacktrace_throw_test/0 line 18
26
+ pr_stacktrace_test:make_throw/0 line 8
27
+throw:{test,exception}",
28
+ ?assertNotEqual(0, string:str(Result, ExpectedPart)).
29
+
30
+
31
+pr_stacktrace_bad_arg_test() ->
32
+ Result = try
33
+ bad_arg()
34
+ catch
35
+ Class:Reason ->
36
+ lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason})
37
+ end,
38
+ExpectedPart = "
39
+ pr_stacktrace_test:pr_stacktrace_bad_arg_test/0 line 32
40
+ pr_stacktrace_test:bad_arg/0 line 14
41
+error:badarg",
42
+ ?assertNotEqual(0, string:str(Result, ExpectedPart)).
43
+
44
+
45
+pr_stacktrace_bad_arity_test() ->
46
+ Result = try
47
+ bad_arity()
48
+ catch
49
+ Class:Reason ->
50
+ lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason})
51
+ end,
52
+ExpectedPart = "
53
+ pr_stacktrace_test:pr_stacktrace_bad_arity_test/0 line 46
54
+ lists:concat([], [])
55
+error:undef",
56
+ ?assertNotEqual(0, string:str(Result, ExpectedPart)).
57
\ No newline at end of file
58
lager-2.1.0.tar.gz/test/trunc_io_eqc.erl -> lager-3.1.0.tar.gz/test/trunc_io_eqc.erl
Changed
10
1
2
3
%% Generates a printable string
4
gen_print_str() ->
5
- ?LET(Xs, list(char()), [X || X <- Xs, io_lib:printable_list([X]), X /= $~, X < 255]).
6
+ ?LET(Xs, list(char()), [X || X <- Xs, io_lib:printable_list([X]), X /= $~, X < 256]).
7
8
gen_print_bin() ->
9
?LET(Xs, gen_print_str(), list_to_binary(Xs)).
10
lager-3.1.0.tar.gz/test/zzzz_gh280_crash.erl
Added
35
1
2
+%% @doc This test is named zzzz_gh280_crash because it has to be run first and tests are run in
3
+%% reverse alphabetical order.
4
+%%
5
+%% The problem we are attempting to detect here is when log_mf_h is installed as a handler for error_logger
6
+%% and lager starts up to replace the current handlers with its own. This causes a start up crash because
7
+%% OTP error logging modules do not have any notion of a lager-style log level.
8
+-module(zzzz_gh280_crash).
9
+-compile(export_all).
10
+
11
+-include_lib("eunit/include/eunit.hrl").
12
+
13
+gh280_crash_test() ->
14
+ application:stop(lager),
15
+ application:stop(goldrush),
16
+
17
+ error_logger:tty(false),
18
+ %% see https://github.com/erlang/otp/blob/maint/lib/stdlib/src/log_mf_h.erl#L81
19
+ %% for an explanation of the init arguments to log_mf_h
20
+ ok = gen_event:add_sup_handler(error_logger, log_mf_h, log_mf_h:init("/tmp", 10000, 5)),
21
+ lager:start(),
22
+ Result = receive
23
+ {gen_event_EXIT,log_mf_h,normal} ->
24
+ true;
25
+ {gen_event_EXIT,Handler,Reason} ->
26
+ {Handler,Reason};
27
+ X ->
28
+ X
29
+ after 1000 ->
30
+ timeout
31
+ end,
32
+ ?assert(Result),
33
+ application:stop(lager),
34
+ application:stop(goldrush).
35
Refresh
Refresh
Login required, please
login
in order to comment
Request History
vanmeeuwen created request over 8 years ago
Submit erlang-lager
vanmeeuwen accepted review over 8 years ago
Accept
vanmeeuwen accepted review over 8 years ago
Accept
vanmeeuwen approved review over 8 years ago
Accept
vanmeeuwen accepted request over 8 years ago
Accept