|
1 -- Prosody IM |
|
2 -- Copyright (C) 2008-2010 Matthew Wild |
|
3 -- Copyright (C) 2008-2010 Waqas Hussain |
|
4 -- |
|
5 -- This project is MIT/X11 licensed. Please see the |
|
6 -- COPYING file in the source package for more information. |
|
7 -- |
|
8 |
|
9 local pcall = pcall; |
|
10 |
|
11 --local log_sources = config.get("*", "core", "log_sources"); |
|
12 |
|
13 local find = string.find; |
|
14 local ipairs, pairs, setmetatable = ipairs, pairs, setmetatable; |
|
15 |
|
16 module "logger" |
|
17 |
|
18 local name_sinks, level_sinks = {}, {}; |
|
19 local name_patterns = {}; |
|
20 |
|
21 -- Weak-keyed so that loggers are collected |
|
22 local modify_hooks = setmetatable({}, { __mode = "k" }); |
|
23 |
|
24 local make_logger; |
|
25 local outfunction = nil; |
|
26 |
|
27 function init(name) |
|
28 if log_sources then |
|
29 local log_this = false; |
|
30 for _, source in ipairs(log_sources) do |
|
31 if find(name, source) then |
|
32 log_this = true; |
|
33 break; |
|
34 end |
|
35 end |
|
36 |
|
37 if not log_this then return function () end end |
|
38 end |
|
39 |
|
40 local log_debug = make_logger(name, "debug"); |
|
41 local log_info = make_logger(name, "info"); |
|
42 local log_warn = make_logger(name, "warn"); |
|
43 local log_error = make_logger(name, "error"); |
|
44 |
|
45 --name = nil; -- While this line is not commented, will automatically fill in file/line number info |
|
46 local namelen = #name; |
|
47 return function (level, message, ...) |
|
48 if outfunction then return outfunction(name, level, message, ...); end |
|
49 |
|
50 if level == "debug" then |
|
51 return log_debug(message, ...); |
|
52 elseif level == "info" then |
|
53 return log_info(message, ...); |
|
54 elseif level == "warn" then |
|
55 return log_warn(message, ...); |
|
56 elseif level == "error" then |
|
57 return log_error(message, ...); |
|
58 end |
|
59 end |
|
60 end |
|
61 |
|
62 function make_logger(source_name, level) |
|
63 local level_handlers = level_sinks[level]; |
|
64 if not level_handlers then |
|
65 level_handlers = {}; |
|
66 level_sinks[level] = level_handlers; |
|
67 end |
|
68 |
|
69 local source_handlers = name_sinks[source_name]; |
|
70 |
|
71 -- All your premature optimisation is belong to me! |
|
72 local num_level_handlers, num_source_handlers = #level_handlers, source_handlers and #source_handlers; |
|
73 |
|
74 local logger = function (message, ...) |
|
75 if source_handlers then |
|
76 for i = 1,num_source_handlers do |
|
77 if source_handlers[i](source_name, level, message, ...) == false then |
|
78 return; |
|
79 end |
|
80 end |
|
81 end |
|
82 |
|
83 for i = 1,num_level_handlers do |
|
84 level_handlers[i](source_name, level, message, ...); |
|
85 end |
|
86 end |
|
87 |
|
88 -- To make sure our cached lengths stay in sync with reality |
|
89 modify_hooks[logger] = function () num_level_handlers, num_source_handlers = #level_handlers, source_handlers and #source_handlers; end; |
|
90 |
|
91 return logger; |
|
92 end |
|
93 |
|
94 function setwriter(f) |
|
95 local old_func = outfunction; |
|
96 if not f then outfunction = nil; return true, old_func; end |
|
97 local ok, ret = pcall(f, "logger", "info", "Switched logging output successfully"); |
|
98 if ok then |
|
99 outfunction = f; |
|
100 ret = old_func; |
|
101 end |
|
102 return ok, ret; |
|
103 end |
|
104 |
|
105 function reset() |
|
106 for k in pairs(name_sinks) do name_sinks[k] = nil; end |
|
107 for level, handler_list in pairs(level_sinks) do |
|
108 -- Clear all handlers for this level |
|
109 for i = 1, #handler_list do |
|
110 handler_list[i] = nil; |
|
111 end |
|
112 end |
|
113 for k in pairs(name_patterns) do name_patterns[k] = nil; end |
|
114 |
|
115 for _, modify_hook in pairs(modify_hooks) do |
|
116 modify_hook(); |
|
117 end |
|
118 end |
|
119 |
|
120 function add_level_sink(level, sink_function) |
|
121 if not level_sinks[level] then |
|
122 level_sinks[level] = { sink_function }; |
|
123 else |
|
124 level_sinks[level][#level_sinks[level] + 1 ] = sink_function; |
|
125 end |
|
126 |
|
127 for _, modify_hook in pairs(modify_hooks) do |
|
128 modify_hook(); |
|
129 end |
|
130 end |
|
131 |
|
132 function add_name_sink(name, sink_function, exclusive) |
|
133 if not name_sinks[name] then |
|
134 name_sinks[name] = { sink_function }; |
|
135 else |
|
136 name_sinks[name][#name_sinks[name] + 1] = sink_function; |
|
137 end |
|
138 |
|
139 for _, modify_hook in pairs(modify_hooks) do |
|
140 modify_hook(); |
|
141 end |
|
142 end |
|
143 |
|
144 function add_name_pattern_sink(name_pattern, sink_function, exclusive) |
|
145 if not name_patterns[name_pattern] then |
|
146 name_patterns[name_pattern] = { sink_function }; |
|
147 else |
|
148 name_patterns[name_pattern][#name_patterns[name_pattern] + 1] = sink_function; |
|
149 end |
|
150 end |
|
151 |
|
152 _M.new = make_logger; |
|
153 |
|
154 return _M; |