Software /
code /
prosody
Comparison
core/loggingmanager.lua @ 1031:ec013f93de81
core.loggingmanager: Refactoring, converted to a module. Now possible to register additional sink types (think syslog) from other modules
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Wed, 22 Apr 2009 19:49:58 +0100 |
parent | 1024:1bcc8ca57a7c |
child | 1046:6fef969ff307 |
comparison
equal
deleted
inserted
replaced
1030:a82268d507fc | 1031:ec013f93de81 |
---|---|
1 | 1 |
2 local format, rep = string.format, string.rep; | 2 local format, rep = string.format, string.rep; |
3 local io_write = io.write; | |
4 local pcall = pcall; | 3 local pcall = pcall; |
5 local debug = debug; | 4 local debug = debug; |
6 local tostring = tostring; | 5 local tostring, setmetatable, rawset, pairs, ipairs, type = |
7 local math_max = math.max; | 6 tostring, setmetatable, rawset, pairs, ipairs, type; |
7 local io_open, io_write = io.open, io.write; | |
8 local math_max, rep = math.max, string.rep; | |
9 local os_getenv = os.getenv; | |
10 local getstyle, getstring = require "util.termcolours".getstyle, require "util.termcolours".getstring; | |
11 | |
12 local config = require "core.configmanager"; | |
8 | 13 |
9 local logger = require "util.logger"; | 14 local logger = require "util.logger"; |
10 | 15 |
16 module "loggingmanager" | |
17 | |
18 -- The log config used if none specified in the config file | |
11 local default_logging = { { to = "console" } }; | 19 local default_logging = { { to = "console" } }; |
12 | 20 |
13 -- Global log function, because some people are too | 21 -- The actual config loggingmanager is using |
14 -- lazy to get their own... | 22 local logging_config = config.get("*", "core", "log") or default_logging; |
15 _G.log = logger.init("general"); | |
16 | 23 |
17 local log_sink_types = {}; | 24 local apply_sink_rules; |
25 local log_sink_types = setmetatable({}, { __newindex = function (t, k, v) rawset(t, k, v); apply_sink_rules(k); end; }); | |
18 local get_levels; | 26 local get_levels; |
19 local logging_levels = { "debug", "info", "warn", "error", "critical" } | 27 local logging_levels = { "debug", "info", "warn", "error", "critical" } |
20 | 28 |
21 --- Main function to read config, create the appropriate sinks and tell logger module | 29 local function add_rule(sink_config) |
22 function setup_logging(log) | 30 local sink_maker = log_sink_types[sink_config.to]; |
23 log = log or config.get("*", "core", "log") or default_logging; | 31 if sink_maker then |
24 -- Set default logger | 32 if sink_config.levels and not sink_config.source then |
25 if type(log) == "string" then | 33 -- Create sink |
26 if not log:match("^%*") then | 34 local sink = sink_maker(sink_config); |
27 end | 35 |
28 elseif type(log) == "table" then | 36 -- Set sink for all chosen levels |
29 -- Advanced configuration chosen | 37 for level in pairs(get_levels(sink_config.levels)) do |
30 for i, sink_config in ipairs(log) do | 38 logger.add_level_sink(level, sink); |
31 local sink_maker = log_sink_types[sink_config.to]; | 39 end |
32 if sink_maker then | 40 elseif sink_config.source and not sink_config.levels then |
33 if sink_config.levels and not sink_config.source then | 41 logger.add_name_sink(sink_config.source, sink_maker(sink_config)); |
34 -- Create sink | 42 elseif sink_config.source and sink_config.levels then |
35 local sink = sink_maker(sink_config); | 43 local levels = get_levels(sink_config.levels); |
36 | 44 local sink = sink_maker(sink_config); |
37 -- Set sink for all chosen levels | 45 logger.add_name_sink(sink_config.source, |
38 for level in pairs(get_levels(sink_config.levels)) do | 46 function (name, level, ...) |
39 logger.add_level_sink(level, sink); | 47 if levels[level] then |
48 return sink(name, level, ...); | |
40 end | 49 end |
41 elseif sink_config.source and not sink_config.levels then | 50 end); |
42 logger.add_name_sink(sink_config.source, sink_maker(sink_config)); | 51 else |
43 elseif sink_config.source and sink_config.levels then | 52 -- All sources |
44 local levels = get_levels(sink_config.levels); | 53 -- Create sink |
45 local sink = sink_maker(sink_config); | 54 local sink = sink_maker(sink_config); |
46 logger.add_name_sink(sink_config.source, | 55 |
47 function (name, level, ...) | 56 -- Set sink for all levels |
48 if levels[level] then | 57 for _, level in pairs(logging_levels) do |
49 return sink(name, level, ...); | 58 logger.add_level_sink(level, sink); |
50 end | |
51 end); | |
52 else | |
53 -- All sources | |
54 -- Create sink | |
55 local sink = sink_maker(sink_config); | |
56 | |
57 -- Set sink for all levels | |
58 for _, level in pairs(logging_levels) do | |
59 logger.add_level_sink(level, sink); | |
60 end | |
61 end | |
62 else | |
63 -- No such sink type | |
64 end | 59 end |
65 end | 60 end |
61 else | |
62 -- No such sink type | |
66 end | 63 end |
67 end | 64 end |
68 | 65 |
69 --- Definition of built-in logging sinks --- | 66 -- Search for all rules using a particular sink type, |
70 local math_max, rep = math.max, string.rep; | 67 -- and apply them |
71 | 68 function apply_sink_rules(sink_type) |
72 -- Column width for "source" (used by stdout and console) | 69 if type(logging_config) == "table" then |
73 | 70 for _, sink_config in pairs(logging_config) do |
74 function log_sink_types.nowhere() | 71 if sink_config.to == sink_type then |
75 return function () return false; end; | 72 add_rule(sink_config); |
76 end | |
77 | |
78 local sourcewidth = 20; | |
79 | |
80 function log_sink_types.stdout() | |
81 return function (name, level, message, ...) | |
82 sourcewidth = math_max(#name+2, sourcewidth); | |
83 local namelen = #name; | |
84 if ... then | |
85 io_write(name, rep(" ", sourcewidth-namelen), level, "\t", format(message, ...), "\n"); | |
86 else | |
87 io_write(name, rep(" ", sourcewidth-namelen), level, "\t", message, "\n"); | |
88 end | |
89 end | |
90 end | |
91 | |
92 do | |
93 local getstyle, getstring = require "util.termcolours".getstyle, require "util.termcolours".getstring; | |
94 local do_pretty_printing = not os.getenv("WINDIR"); | |
95 | |
96 local logstyles = {}; | |
97 if do_pretty_printing then | |
98 logstyles["info"] = getstyle("bold"); | |
99 logstyles["warn"] = getstyle("bold", "yellow"); | |
100 logstyles["error"] = getstyle("bold", "red"); | |
101 end | |
102 function log_sink_types.console(config) | |
103 -- Really if we don't want pretty colours then just use plain stdout | |
104 if not do_pretty_printing then | |
105 return log_sink_types.stdout(config); | |
106 end | |
107 | |
108 return function (name, level, message, ...) | |
109 sourcewidth = math_max(#name+2, sourcewidth); | |
110 local namelen = #name; | |
111 if ... then | |
112 io_write(name, rep(" ", sourcewidth-namelen), getstring(logstyles[level], level), "\t", format(message, ...), "\n"); | |
113 else | |
114 io_write(name, rep(" ", sourcewidth-namelen), getstring(logstyles[level], level), "\t", message, "\n"); | |
115 end | 73 end |
116 end | 74 end |
75 elseif type(logging_config) == "string" and sink_type == "file" then | |
76 -- User specified simply a filename, and the "file" sink type | |
77 -- was just added | |
117 end | 78 end |
118 end | 79 end |
119 | 80 |
120 function log_sink_types.file(config) | |
121 local log = config.filename; | |
122 local logfile = io.open(log, "a+"); | |
123 if not logfile then | |
124 return function () end | |
125 end | |
126 | 81 |
127 local write, format, flush = logfile.write, string.format, logfile.flush; | |
128 return function (name, level, message, ...) | |
129 if ... then | |
130 write(logfile, name, "\t", level, "\t", format(message, ...), "\n"); | |
131 else | |
132 write(logfile, name, "\t" , level, "\t", message, "\n"); | |
133 end | |
134 flush(logfile); | |
135 end; | |
136 end | |
137 | |
138 function log_sink_types.syslog() | |
139 end | |
140 | 82 |
141 --- Helper function to get a set of levels given a "criteria" table | 83 --- Helper function to get a set of levels given a "criteria" table |
142 function get_levels(criteria, set) | 84 function get_levels(criteria, set) |
143 set = set or {}; | 85 set = set or {}; |
144 if type(criteria) == "string" then | 86 if type(criteria) == "string" then |
165 set[level] = true; | 107 set[level] = true; |
166 end | 108 end |
167 return set; | 109 return set; |
168 end | 110 end |
169 | 111 |
170 --- Set up logging | 112 --- Definition of built-in logging sinks --- |
171 setup_logging(); | |
172 | 113 |
114 function log_sink_types.nowhere() | |
115 return function () return false; end; | |
116 end | |
117 | |
118 -- Column width for "source" (used by stdout and console) | |
119 local sourcewidth = 20; | |
120 | |
121 function log_sink_types.stdout() | |
122 return function (name, level, message, ...) | |
123 sourcewidth = math_max(#name+2, sourcewidth); | |
124 local namelen = #name; | |
125 if ... then | |
126 io_write(name, rep(" ", sourcewidth-namelen), level, "\t", format(message, ...), "\n"); | |
127 else | |
128 io_write(name, rep(" ", sourcewidth-namelen), level, "\t", message, "\n"); | |
129 end | |
130 end | |
131 end | |
132 | |
133 do | |
134 local do_pretty_printing = not os_getenv("WINDIR"); | |
135 | |
136 local logstyles = {}; | |
137 if do_pretty_printing then | |
138 logstyles["info"] = getstyle("bold"); | |
139 logstyles["warn"] = getstyle("bold", "yellow"); | |
140 logstyles["error"] = getstyle("bold", "red"); | |
141 end | |
142 function log_sink_types.console(config) | |
143 -- Really if we don't want pretty colours then just use plain stdout | |
144 if not do_pretty_printing then | |
145 return log_sink_types.stdout(config); | |
146 end | |
147 | |
148 return function (name, level, message, ...) | |
149 sourcewidth = math_max(#name+2, sourcewidth); | |
150 local namelen = #name; | |
151 if ... then | |
152 io_write(name, rep(" ", sourcewidth-namelen), getstring(logstyles[level], level), "\t", format(message, ...), "\n"); | |
153 else | |
154 io_write(name, rep(" ", sourcewidth-namelen), getstring(logstyles[level], level), "\t", message, "\n"); | |
155 end | |
156 end | |
157 end | |
158 end | |
159 | |
160 function log_sink_types.file(config) | |
161 local log = config.filename; | |
162 local logfile = io_open(log, "a+"); | |
163 if not logfile then | |
164 return function () end | |
165 end | |
166 | |
167 local write, format, flush = logfile.write, format, logfile.flush; | |
168 return function (name, level, message, ...) | |
169 if ... then | |
170 write(logfile, name, "\t", level, "\t", format(message, ...), "\n"); | |
171 else | |
172 write(logfile, name, "\t" , level, "\t", message, "\n"); | |
173 end | |
174 flush(logfile); | |
175 end; | |
176 end | |
177 | |
178 function register_sink_type(name, sink_maker) | |
179 local old_sink_maker = log_sink_types[name]; | |
180 log_sink_types[name] = sink_maker; | |
181 return old_sink_maker; | |
182 end | |
183 | |
184 return _M; |