Mercurial > prosody-hg
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 |
| parents | 1bcc8ca57a7c |
| children | 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; |
