Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 269 lines (237 sloc) 10.112 kb
12a784b @Vagabond Time makes fools of us all
Vagabond authored
1 %% Copyright (c) 2011-2012 Basho Technologies, Inc. All Rights Reserved.
7bcf044 @Vagabond Initial import
Vagabond authored
2 %%
3 %% This file is provided to you under the Apache License,
4 %% Version 2.0 (the "License"); you may not use this file
5 %% except in compliance with the License. You may obtain
6 %% a copy of the License at
7 %%
8 %% http://www.apache.org/licenses/LICENSE-2.0
9 %%
10 %% Unless required by applicable law or agreed to in writing,
11 %% software distributed under the License is distributed on an
12 %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 %% KIND, either express or implied. See the License for the
14 %% specific language governing permissions and limitations
15 %% under the License.
16
862a9cb @Vagabond Documentation!
Vagabond authored
17 %% @doc The lager logging framework.
18
7bcf044 @Vagabond Initial import
Vagabond authored
19 -module(lager).
20
886d410 @Vagabond Make highest log level be 0; add some helper macros
Vagabond authored
21 -include("lager.hrl").
0415d21 @nialscorva Changed the messages sent to the backends to include metadata and separa...
nialscorva authored
22 -include_lib("eunit/include/eunit.hrl").
886d410 @Vagabond Make highest log level be 0; add some helper macros
Vagabond authored
23
761642e @Vagabond Add ability to adjust loglevel per handler at runtime
Vagabond authored
24 %% API
a6cbc19 @Vagabond Rework supervisor tree to be more sane
Vagabond authored
25 -export([start/0,
0415d21 @nialscorva Changed the messages sent to the backends to include metadata and separa...
nialscorva authored
26 log/3, log/4,
96e9f6e @Vagabond Add a function for removing an active trace
Vagabond authored
27 trace_file/2, trace_file/3, trace_console/1, trace_console/2,
28 clear_all_traces/0, stop_trace/1, status/0,
a6cbc19 @Vagabond Rework supervisor tree to be more sane
Vagabond authored
29 get_loglevel/1, set_loglevel/2, set_loglevel/3, get_loglevels/0,
cf51ba0 @slfritchie Rename format_string_chop() -> safe_format_chop(), add -export
slfritchie authored
30 minimum_loglevel/1, posix_error/1,
0415d21 @nialscorva Changed the messages sent to the backends to include metadata and separa...
nialscorva authored
31 safe_format/3, safe_format_chop/3,dispatch_log/5]).
7bcf044 @Vagabond Initial import
Vagabond authored
32
ec61e88 @Vagabond Make the dialyzer happy.
Vagabond authored
33 -type log_level() :: debug | info | notice | warning | error | critical | alert | emergency.
34 -type log_level_number() :: 0..7.
35
36 -export_type([log_level/0, log_level_number/0]).
37
7bcf044 @Vagabond Initial import
Vagabond authored
38 %% API
39
862a9cb @Vagabond Documentation!
Vagabond authored
40 %% @doc Start the application. Mainly useful for using `-s lager' as a command
41 %% line switch to the VM to make lager start on boot.
a6cbc19 @Vagabond Rework supervisor tree to be more sane
Vagabond authored
42 start() -> start(lager).
43
44 start(App) ->
45 start_ok(App, application:start(App, permanent)).
7bcf044 @Vagabond Initial import
Vagabond authored
46
a6cbc19 @Vagabond Rework supervisor tree to be more sane
Vagabond authored
47 start_ok(_App, ok) -> ok;
48 start_ok(_App, {error, {already_started, _App}}) -> ok;
80a0e9f @devinus Add support for a custom log truncation size compile time flag
devinus authored
49 start_ok(App, {error, {not_started, Dep}}) ->
a6cbc19 @Vagabond Rework supervisor tree to be more sane
Vagabond authored
50 ok = start(Dep),
51 start(App);
80a0e9f @devinus Add support for a custom log truncation size compile time flag
devinus authored
52 start_ok(App, {error, Reason}) ->
a6cbc19 @Vagabond Rework supervisor tree to be more sane
Vagabond authored
53 erlang:error({app_start_failed, App, Reason}).
7bcf044 @Vagabond Initial import
Vagabond authored
54
2f9b793 @nialscorva Moved a lot of the AST in lager_transform into a function to make things...
nialscorva authored
55
7b05164 @Vagabond Change the default formatter to be backwards compatible with old behavio...
Vagabond authored
56 -spec dispatch_log(log_level(), list(), string(), list() | none, pos_integer()) -> ok | {error, lager_not_running}.
0415d21 @nialscorva Changed the messages sent to the backends to include metadata and separa...
nialscorva authored
57 dispatch_log(Severity, Metadata, Format, Args, Size) when is_atom(Severity)->
58 case whereis(lager_event) of
59 undefined ->
60 %% lager isn't running
61 {error, lager_not_running};
62 Pid ->
63 {LevelThreshold,TraceFilters} = lager_mochiglobal:get(loglevel,{?LOG_NONE,[]}),
64 SeverityAsInt=lager_util:level_to_num(Severity),
65 Destinations = case TraceFilters of
66 [] -> [];
67 _ ->
68 lager_util:check_traces(Metadata,SeverityAsInt,TraceFilters,[])
69 end,
70 case (LevelThreshold >= SeverityAsInt orelse Destinations =/= []) of
71 true ->
72 Timestamp = lager_util:format_time(),
73 Msg=case Args of
7b05164 @Vagabond Change the default formatter to be backwards compatible with old behavio...
Vagabond authored
74 A when is_list(A) ->safe_format_chop(Format,Args,Size);
0415d21 @nialscorva Changed the messages sent to the backends to include metadata and separa...
nialscorva authored
75 _ -> Format
76 end,
e04830b @Vagabond Tag lager_msg messages with a {log, ...} tuple
Vagabond authored
77 gen_event:sync_notify(Pid, {log, lager_msg:new(Msg, Timestamp,
78 Severity, Metadata, Destinations)});
0415d21 @nialscorva Changed the messages sent to the backends to include metadata and separa...
nialscorva authored
79 _ ->
80 ok
81 end
2f9b793 @nialscorva Moved a lot of the AST in lager_transform into a function to make things...
nialscorva authored
82 end.
83
862a9cb @Vagabond Documentation!
Vagabond authored
84 %% @doc Manually log a message into lager without using the parse transform.
bc338b2 @Vagabond Fix dialyzer warnings
Vagabond authored
85 -spec log(log_level(), pid() | [tuple(),...], list()) -> ok | {error, lager_not_running}.
7b05164 @Vagabond Change the default formatter to be backwards compatible with old behavio...
Vagabond authored
86 log(Level, Pid, Message) when is_pid(Pid) ->
55283cc @Vagabond Make the default truncation limit a macro
Vagabond authored
87 dispatch_log(Level, [{pid,Pid}], Message, [], ?DEFAULT_TRUNCATION);
7b05164 @Vagabond Change the default formatter to be backwards compatible with old behavio...
Vagabond authored
88 log(Level, Metadata, Message) when is_list(Metadata) ->
55283cc @Vagabond Make the default truncation limit a macro
Vagabond authored
89 dispatch_log(Level, Metadata, Message, [], ?DEFAULT_TRUNCATION).
04792f1 @Vagabond Initial version of error_logger->lager translator
Vagabond authored
90
862a9cb @Vagabond Documentation!
Vagabond authored
91 %% @doc Manually log a message into lager without using the parse transform.
bc338b2 @Vagabond Fix dialyzer warnings
Vagabond authored
92 -spec log(log_level(), pid() | [tuple(),...], string(), list()) -> ok | {error, lager_not_running}.
7b05164 @Vagabond Change the default formatter to be backwards compatible with old behavio...
Vagabond authored
93 log(Level, Pid, Format, Args) when is_pid(Pid) ->
55283cc @Vagabond Make the default truncation limit a macro
Vagabond authored
94 dispatch_log(Level, [{pid,Pid}], Format, Args, ?DEFAULT_TRUNCATION);
7b05164 @Vagabond Change the default formatter to be backwards compatible with old behavio...
Vagabond authored
95 log(Level, Metadata, Format, Args) when is_list(Metadata) ->
55283cc @Vagabond Make the default truncation limit a macro
Vagabond authored
96 dispatch_log(Level, Metadata, Format, Args, ?DEFAULT_TRUNCATION).
04792f1 @Vagabond Initial version of error_logger->lager translator
Vagabond authored
97
d28e7c5 @Vagabond Initial attempt at a trace API, and a status() command
Vagabond authored
98 trace_file(File, Filter) ->
99 trace_file(File, Filter, debug).
100
101 trace_file(File, Filter, Level) ->
102 Trace0 = {Filter, Level, {lager_file_backend, File}},
103 case lager_util:validate_trace(Trace0) of
104 {ok, Trace} ->
105 Handlers = gen_event:which_handlers(lager_event),
106 %% check if this file backend is already installed
efc7b75 @Vagabond Changes suggested by Kostis, Dialyzer -Wunmatched_returns and Tidier
Vagabond authored
107 Res = case lists:member({lager_file_backend, File}, Handlers) of
d28e7c5 @Vagabond Initial attempt at a trace API, and a status() command
Vagabond authored
108 false ->
109 %% install the handler
7815a88 @Vagabond Fix the Fix for the Fix for #49, thanks to Kostis for keeping me honest
Vagabond authored
110 supervisor:start_child(lager_handler_watcher_sup,
111 [lager_event, {lager_file_backend, File}, {File, none}]);
d28e7c5 @Vagabond Initial attempt at a trace API, and a status() command
Vagabond authored
112 _ ->
7815a88 @Vagabond Fix the Fix for the Fix for #49, thanks to Kostis for keeping me honest
Vagabond authored
113 {ok, exists}
d28e7c5 @Vagabond Initial attempt at a trace API, and a status() command
Vagabond authored
114 end,
efc7b75 @Vagabond Changes suggested by Kostis, Dialyzer -Wunmatched_returns and Tidier
Vagabond authored
115 case Res of
7815a88 @Vagabond Fix the Fix for the Fix for #49, thanks to Kostis for keeping me honest
Vagabond authored
116 {ok, _} ->
efc7b75 @Vagabond Changes suggested by Kostis, Dialyzer -Wunmatched_returns and Tidier
Vagabond authored
117 %% install the trace.
118 {MinLevel, Traces} = lager_mochiglobal:get(loglevel),
119 case lists:member(Trace, Traces) of
120 false ->
bd9b66a @Vagabond Don't allow a trace to be installed twice
Vagabond authored
121 lager_mochiglobal:put(loglevel, {MinLevel, [Trace|Traces]});
efc7b75 @Vagabond Changes suggested by Kostis, Dialyzer -Wunmatched_returns and Tidier
Vagabond authored
122 _ ->
123 ok
124 end,
125 {ok, Trace};
126 {error, _} = E ->
127 E
128 end;
d28e7c5 @Vagabond Initial attempt at a trace API, and a status() command
Vagabond authored
129 Error ->
130 Error
131 end.
132
133 trace_console(Filter) ->
ac8fb19 @Vagabond Implement console tracing, don't generate duplicate messages
Vagabond authored
134 trace_console(Filter, debug).
d28e7c5 @Vagabond Initial attempt at a trace API, and a status() command
Vagabond authored
135
136 trace_console(Filter, Level) ->
137 Trace0 = {Filter, Level, lager_console_backend},
138 case lager_util:validate_trace(Trace0) of
139 {ok, Trace} ->
ac8fb19 @Vagabond Implement console tracing, don't generate duplicate messages
Vagabond authored
140 {MinLevel, Traces} = lager_mochiglobal:get(loglevel),
bd9b66a @Vagabond Don't allow a trace to be installed twice
Vagabond authored
141 case lists:member(Trace, Traces) of
142 false ->
143 lager_mochiglobal:put(loglevel, {MinLevel, [Trace|Traces]});
144 _ -> ok
145 end,
96e9f6e @Vagabond Add a function for removing an active trace
Vagabond authored
146 {ok, Trace};
d28e7c5 @Vagabond Initial attempt at a trace API, and a status() command
Vagabond authored
147 Error ->
148 Error
149 end.
150
c619263 @Vagabond Cleanup unused handlers when a trace is removed, documentation
Vagabond authored
151 stop_trace({_Filter, _Level, Target} = Trace) ->
96e9f6e @Vagabond Add a function for removing an active trace
Vagabond authored
152 {MinLevel, Traces} = lager_mochiglobal:get(loglevel),
c619263 @Vagabond Cleanup unused handlers when a trace is removed, documentation
Vagabond authored
153 NewTraces = lists:delete(Trace, Traces),
154 lager_mochiglobal:put(loglevel, {MinLevel, NewTraces}),
155 case get_loglevel(Target) of
156 none ->
157 %% check no other traces point here
158 case lists:keyfind(Target, 3, NewTraces) of
159 false ->
160 gen_event:delete_handler(lager_event, Target, []);
161 _ ->
162 ok
163 end;
164 _ ->
165 ok
166 end,
96e9f6e @Vagabond Add a function for removing an active trace
Vagabond authored
167 ok.
168
0e70e68 @Vagabond Add documentation & function to clear all traces
Vagabond authored
169 clear_all_traces() ->
170 {MinLevel, _Traces} = lager_mochiglobal:get(loglevel),
c619263 @Vagabond Cleanup unused handlers when a trace is removed, documentation
Vagabond authored
171 lager_mochiglobal:put(loglevel, {MinLevel, []}),
efc7b75 @Vagabond Changes suggested by Kostis, Dialyzer -Wunmatched_returns and Tidier
Vagabond authored
172 lists:foreach(fun(Handler) ->
173 case get_loglevel(Handler) of
174 none ->
175 gen_event:delete_handler(lager_event, Handler, []);
176 _ ->
177 ok
178 end
179 end, gen_event:which_handlers(lager_event)).
0e70e68 @Vagabond Add documentation & function to clear all traces
Vagabond authored
180
d28e7c5 @Vagabond Initial attempt at a trace API, and a status() command
Vagabond authored
181 status() ->
182 Handlers = gen_event:which_handlers(lager_event),
183 Status = ["Lager status:\n",
184 [begin
185 Level = get_loglevel(Handler),
186 case Handler of
187 {lager_file_backend, File} ->
188 io_lib:format("File ~s at level ~p\n", [File, Level]);
189 lager_console_backend ->
190 io_lib:format("Console at level ~p\n", [Level]);
191 _ ->
192 []
193 end
194 end || Handler <- Handlers],
195 "Active Traces:\n",
196 [begin
0e70e68 @Vagabond Add documentation & function to clear all traces
Vagabond authored
197 io_lib:format("Tracing messages matching ~p at level ~p to ~p\n",
198 [Filter, lager_util:num_to_level(Level), Destination])
d28e7c5 @Vagabond Initial attempt at a trace API, and a status() command
Vagabond authored
199 end || {Filter, Level, Destination} <- element(2, lager_mochiglobal:get(loglevel))]],
200 io:put_chars(Status).
04792f1 @Vagabond Initial version of error_logger->lager translator
Vagabond authored
201
862a9cb @Vagabond Documentation!
Vagabond authored
202 %% @doc Set the loglevel for a particular backend.
761642e @Vagabond Add ability to adjust loglevel per handler at runtime
Vagabond authored
203 set_loglevel(Handler, Level) when is_atom(Level) ->
3e3bed6 @Vagabond Set gen_event:call timeout to infinity.
Vagabond authored
204 Reply = gen_event:call(lager_event, Handler, {set_loglevel, Level}, infinity),
a6cbc19 @Vagabond Rework supervisor tree to be more sane
Vagabond authored
205 %% recalculate min log level
206 MinLog = minimum_loglevel(get_loglevels()),
121c4c5 @Vagabond Initial implementation of 'tracing'
Vagabond authored
207 {_, Traces} = lager_mochiglobal:get(loglevel),
208 lager_mochiglobal:put(loglevel, {MinLog, Traces}),
a6cbc19 @Vagabond Rework supervisor tree to be more sane
Vagabond authored
209 Reply.
761642e @Vagabond Add ability to adjust loglevel per handler at runtime
Vagabond authored
210
862a9cb @Vagabond Documentation!
Vagabond authored
211 %% @doc Set the loglevel for a particular backend that has multiple identifiers
212 %% (eg. the file backend).
761642e @Vagabond Add ability to adjust loglevel per handler at runtime
Vagabond authored
213 set_loglevel(Handler, Ident, Level) when is_atom(Level) ->
e3e8c80 @Vagabond Fix loglevel changes for files, now they've been refactored
Vagabond authored
214 io:format("handler: ~p~n", [{Handler, Ident}]),
215 Reply = gen_event:call(lager_event, {Handler, Ident}, {set_loglevel, Level}, infinity),
a6cbc19 @Vagabond Rework supervisor tree to be more sane
Vagabond authored
216 %% recalculate min log level
217 MinLog = minimum_loglevel(get_loglevels()),
121c4c5 @Vagabond Initial implementation of 'tracing'
Vagabond authored
218 {_, Traces} = lager_mochiglobal:get(loglevel),
219 lager_mochiglobal:put(loglevel, {MinLog, Traces}),
a6cbc19 @Vagabond Rework supervisor tree to be more sane
Vagabond authored
220 Reply.
761642e @Vagabond Add ability to adjust loglevel per handler at runtime
Vagabond authored
221
862a9cb @Vagabond Documentation!
Vagabond authored
222 %% @doc Get the loglevel for a particular backend. In the case that the backend
223 %% has multiple identifiers, the lowest is returned
761642e @Vagabond Add ability to adjust loglevel per handler at runtime
Vagabond authored
224 get_loglevel(Handler) ->
3e3bed6 @Vagabond Set gen_event:call timeout to infinity.
Vagabond authored
225 case gen_event:call(lager_event, Handler, get_loglevel, infinity) of
761642e @Vagabond Add ability to adjust loglevel per handler at runtime
Vagabond authored
226 X when is_integer(X) ->
ec61e88 @Vagabond Make the dialyzer happy.
Vagabond authored
227 lager_util:num_to_level(X);
761642e @Vagabond Add ability to adjust loglevel per handler at runtime
Vagabond authored
228 Y -> Y
229 end.
230
dfa91d8 @Vagabond Add a function for printing POSIX error codes as messages
Vagabond authored
231 %% @doc Try to convert an atom to a posix error, but fall back on printing the
232 %% term if its not a valid posix error code.
233 posix_error(Error) when is_atom(Error) ->
234 case erl_posix_msg:message(Error) of
235 "unknown POSIX error" -> atom_to_list(Error);
236 Message -> Message
237 end;
238 posix_error(Error) ->
55283cc @Vagabond Make the default truncation limit a macro
Vagabond authored
239 safe_format_chop("~p", [Error], ?DEFAULT_TRUNCATION).
dfa91d8 @Vagabond Add a function for printing POSIX error codes as messages
Vagabond authored
240
862a9cb @Vagabond Documentation!
Vagabond authored
241 %% @private
a6cbc19 @Vagabond Rework supervisor tree to be more sane
Vagabond authored
242 get_loglevels() ->
3e3bed6 @Vagabond Set gen_event:call timeout to infinity.
Vagabond authored
243 [gen_event:call(lager_event, Handler, get_loglevel, infinity) ||
7bcf044 @Vagabond Initial import
Vagabond authored
244 Handler <- gen_event:which_handlers(lager_event)].
245
862a9cb @Vagabond Documentation!
Vagabond authored
246 %% @private
a6cbc19 @Vagabond Rework supervisor tree to be more sane
Vagabond authored
247 minimum_loglevel([]) ->
886d410 @Vagabond Make highest log level be 0; add some helper macros
Vagabond authored
248 -1; %% lower than any log level, logging off
a6cbc19 @Vagabond Rework supervisor tree to be more sane
Vagabond authored
249 minimum_loglevel(Levels) ->
886d410 @Vagabond Make highest log level be 0; add some helper macros
Vagabond authored
250 erlang:hd(lists:reverse(lists:sort(Levels))).
077f218 @Vagabond Make logging not crash when lager is not running
Vagabond authored
251
eea29be @slfritchie Rework using safe_format() from one of Andrew's branches
slfritchie authored
252 %% @doc Print the format string `Fmt' with `Args' safely with a size
253 %% limit of `Limit'. If the format string is invalid, or not enough
254 %% arguments are supplied 'FORMAT ERROR' is printed with the offending
255 %% arguments. The caller is NOT crashed.
256
257 safe_format(Fmt, Args, Limit) ->
3311702 @Vagabond Add builtin chomping to lager_format
Vagabond authored
258 safe_format(Fmt, Args, Limit, []).
259
260 safe_format(Fmt, Args, Limit, Options) ->
efc7b75 @Vagabond Changes suggested by Kostis, Dialyzer -Wunmatched_returns and Tidier
Vagabond authored
261 try lager_trunc_io:format(Fmt, Args, Limit, Options)
eea29be @slfritchie Rework using safe_format() from one of Andrew's branches
slfritchie authored
262 catch
263 _:_ -> lager_trunc_io:format("FORMAT ERROR: ~p ~p", [Fmt, Args], Limit)
264 end.
265
9a6aff4 @slfritchie Add lager:log() message size truncation
slfritchie authored
266 %% @private
cf51ba0 @slfritchie Rename format_string_chop() -> safe_format_chop(), add -export
slfritchie authored
267 safe_format_chop(Fmt, Args, Limit) ->
3311702 @Vagabond Add builtin chomping to lager_format
Vagabond authored
268 safe_format(Fmt, Args, Limit, [{chomp, true}]).
Something went wrong with that request. Please try again.