util/logger.lua

changeset 1015
9e31e9397cff
parent 977
6f0bdf9e4dfb
child 1020
8bf71f8bd0d1
equal deleted inserted replaced
1013:c500d4cb7855 1015:9e31e9397cff
4 -- 4 --
5 -- This project is MIT/X11 licensed. Please see the 5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information. 6 -- COPYING file in the source package for more information.
7 -- 7 --
8 8
9 local format, rep = string.format, string.rep;
10 local io_write = io.write;
11 local pcall = pcall; 9 local pcall = pcall;
12 local debug = debug;
13 local tostring = tostring;
14 local math_max = math.max;
15 10
16 local config = require "core.configmanager"; 11 local config = require "core.configmanager";
17 local log_sources = config.get("*", "core", "log_sources"); 12 local log_sources = config.get("*", "core", "log_sources");
18 13
19 local getstyle, getstring = require "util.termcolours".getstyle, require "util.termcolours".getstring;
20 local do_pretty_printing = not os.getenv("WINDIR");
21 local find = string.find; 14 local find = string.find;
22 local ipairs = ipairs; 15 local ipairs, pairs, setmetatable = ipairs, pairs, setmetatable;
23 16
24 module "logger" 17 module "logger"
25 18
26 local logstyles = {}; 19 local name_sinks, level_sinks = {}, {};
20 local name_patterns = {};
27 21
28 --TODO: This should be done in config, but we don't have proper config yet 22 -- Weak-keyed so that loggers are collected
29 if do_pretty_printing then 23 local modify_hooks = setmetatable({}, { __mode = "k" });
30 logstyles["info"] = getstyle("bold");
31 logstyles["warn"] = getstyle("bold", "yellow");
32 logstyles["error"] = getstyle("bold", "red");
33 end
34 24
35 local sourcewidth = 20; 25 local make_logger;
36
37 local outfunction = nil; 26 local outfunction = nil;
38 27
39 function init(name) 28 function init(name)
40 if log_sources then 29 if log_sources then
41 local log_this = false; 30 local log_this = false;
47 end 36 end
48 37
49 if not log_this then return function () end end 38 if not log_this then return function () end end
50 end 39 end
51 40
41 local log_debug = make_logger(name, "debug");
42 local log_info = make_logger(name, "info");
43 local log_warn = make_logger(name, "warn");
44 local log_error = make_logger(name, "error");
45
52 --name = nil; -- While this line is not commented, will automatically fill in file/line number info 46 --name = nil; -- While this line is not commented, will automatically fill in file/line number info
53 local namelen = #name; 47 local namelen = #name;
54 return function (level, message, ...) 48 return function (level, message, ...)
55 if outfunction then return outfunction(name, level, message, ...); end 49 if outfunction then return outfunction(name, level, message, ...); end
56 50
57 sourcewidth = math_max(#name+2, sourcewidth); 51 if level == "debug" then
58 if ... then 52 return log_debug(message, ...);
59 io_write(name, rep(" ", sourcewidth-namelen), getstring(logstyles[level], level), "\t", format(message, ...), "\n"); 53 elseif level == "info" then
60 else 54 return log_info(message, ...);
61 io_write(name, rep(" ", sourcewidth-namelen), getstring(logstyles[level], level), "\t", message, "\n"); 55 elseif level == "warn" then
56 return log_warn(message, ...);
57 elseif level == "error" then
58 return log_error(message, ...);
59 end
60 end
61 end
62
63 function make_logger(source_name, level)
64 local level_handlers = level_sinks[level];
65 if not level_handlers then
66 level_handlers = {};
67 level_sinks[level] = level_handlers;
68 end
69
70 local source_handlers = name_sinks[source_name];
71
72 -- All your premature optimisation is belong to me!
73 local num_level_handlers, num_source_handlers = #level_handlers, source_handlers and #source_handlers;
74
75 local logger = function (message, ...)
76 if source_handlers then
77 for i = 1,num_source_handlers do
78 if source_handlers(source_name, level, message, ...) == false then
79 return;
62 end 80 end
63 end 81 end
82 end
83
84 for i = 1,num_level_handlers do
85 level_handlers[i](source_name, level, message, ...);
86 end
87 end
88
89 -- To make sure our cached lengths stay in sync with reality
90 modify_hooks[logger] = function () num_level_handlers, num_source_handlers = #level_handlers, source_handlers and #source_handlers; end;
91
92 return logger;
64 end 93 end
65 94
66 function setwriter(f) 95 function setwriter(f)
67 local old_func = outfunction; 96 local old_func = outfunction;
68 if not f then outfunction = nil; return true, old_func; end 97 if not f then outfunction = nil; return true, old_func; end
72 ret = old_func; 101 ret = old_func;
73 end 102 end
74 return ok, ret; 103 return ok, ret;
75 end 104 end
76 105
106 function add_level_sink(level, sink_function)
107 if not level_sinks[level] then
108 level_sinks[level] = { sink_function };
109 else
110 level_sinks[level][#level_sinks[level] + 1 ] = sink_function;
111 end
112
113 for _, modify_hook in pairs(modify_hooks) do
114 modify_hook();
115 end
116 end
117
118 function add_name_sink(name, sink_function, exclusive)
119 if not name_sinks[name] then
120 name_sinks[name] = { sink_function };
121 else
122 name_sinks[name][#name_sinks[name] + 1] = sink_function;
123 end
124
125 for _, modify_hook in pairs(modify_hooks) do
126 modify_hook();
127 end
128 end
129
130 function add_name_pattern_sink(name_pattern, sink_function, exclusive)
131 if not name_patterns[name_pattern] then
132 name_patterns[name_pattern] = { sink_function };
133 else
134 name_patterns[name_pattern][#name_patterns[name_pattern] + 1] = sink_function;
135 end
136 end
137
138 _M.new = make_logger;
139
77 return _M; 140 return _M;

mercurial