2 -- Copyright (C) 2008-2010 Matthew Wild
3 -- Copyright (C) 2008-2010 Waqas Hussain
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
11 local find = string.find;
12 local ipairs, pairs, setmetatable = ipairs, pairs, setmetatable;
16 local name_sinks, level_sinks = {}, {};
17 local name_patterns = {};
19 -- Weak-keyed so that loggers are collected
20 local modify_hooks = setmetatable({}, { __mode = "k" });
23 local outfunction = nil;
26 local log_debug = make_logger(name, "debug");
27 local log_info = make_logger(name, "info");
28 local log_warn = make_logger(name, "warn");
29 local log_error = make_logger(name, "error");
31 --name = nil; -- While this line is not commented, will automatically fill in file/line number info
32 local namelen = #name;
33 return function (level, message, ...)
34 if outfunction then return outfunction(name, level, message, ...); end
36 if level == "debug" then
37 return log_debug(message, ...);
38 elseif level == "info" then
39 return log_info(message, ...);
40 elseif level == "warn" then
41 return log_warn(message, ...);
42 elseif level == "error" then
43 return log_error(message, ...);
48 function make_logger(source_name, level)
49 local level_handlers = level_sinks[level];
50 if not level_handlers then
52 level_sinks[level] = level_handlers;
55 local source_handlers = name_sinks[source_name];
57 -- All your premature optimisation is belong to me!
58 local num_level_handlers, num_source_handlers = #level_handlers, source_handlers and #source_handlers;
60 local logger = function (message, ...)
61 if source_handlers then
62 for i = 1,num_source_handlers do
63 if source_handlers[i](source_name, level, message, ...) == false then
69 for i = 1,num_level_handlers do
70 level_handlers[i](source_name, level, message, ...);
74 -- To make sure our cached lengths stay in sync with reality
75 modify_hooks[logger] = function () num_level_handlers, num_source_handlers = #level_handlers, source_handlers and #source_handlers; end;
81 local old_func = outfunction;
82 if not f then outfunction = nil; return true, old_func; end
83 local ok, ret = pcall(f, "logger", "info", "Switched logging output successfully");
92 for k in pairs(name_sinks) do name_sinks[k] = nil; end
93 for level, handler_list in pairs(level_sinks) do
94 -- Clear all handlers for this level
95 for i = 1, #handler_list do
96 handler_list[i] = nil;
99 for k in pairs(name_patterns) do name_patterns[k] = nil; end
101 for _, modify_hook in pairs(modify_hooks) do
106 function add_level_sink(level, sink_function)
107 if not level_sinks[level] then
108 level_sinks[level] = { sink_function };
110 level_sinks[level][#level_sinks[level] + 1 ] = sink_function;
113 for _, modify_hook in pairs(modify_hooks) do
118 function add_name_sink(name, sink_function, exclusive)
119 if not name_sinks[name] then
120 name_sinks[name] = { sink_function };
122 name_sinks[name][#name_sinks[name] + 1] = sink_function;
125 for _, modify_hook in pairs(modify_hooks) do
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 };
134 name_patterns[name_pattern][#name_patterns[name_pattern] + 1] = sink_function;
138 _M.new = make_logger;