util.pluginloader: Return full file path from internal file loader on success, not...
[prosody.git] / util / logger.lua
index fab9e4c39652e28ce0bd62e8fab2aa486c34feeb..c3bf399266703a6832e30ed14c6ab42183052c4e 100644 (file)
--- Prosody IM v0.4
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Prosody IM
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
 --
 
-local format, rep = string.format, string.rep;
-local io_write = io.write;
 local pcall = pcall;
-local debug = debug;
-local tostring = tostring;
-local math_max = math.max;
 
-local config = require "core.configmanager";
-local log_sources = config.get("*", "core", "log_sources");
-
-local getstyle, getstring = require "util.termcolours".getstyle, require "util.termcolours".getstring;
-local do_pretty_printing = not os.getenv("WINDIR");
 local find = string.find;
-local ipairs = ipairs;
+local ipairs, pairs, setmetatable = ipairs, pairs, setmetatable;
 
 module "logger"
 
-local logstyles = {};
-
---TODO: This should be done in config, but we don't have proper config yet
-if do_pretty_printing then
-       logstyles["info"] = getstyle("bold");
-       logstyles["warn"] = getstyle("bold", "yellow");
-       logstyles["error"] = getstyle("bold", "red");
-end
-
-local sourcewidth = 20;
+local name_sinks, level_sinks = {}, {};
+local name_patterns = {};
 
-local outfunction = nil;
+local make_logger;
 
 function init(name)
-       if log_sources then
-               local log_this = false;
-               for _, source in ipairs(log_sources) do
-                       if find(name, source) then 
-                               log_this = true;
-                               break;
+       local log_debug = make_logger(name, "debug");
+       local log_info = make_logger(name, "info");
+       local log_warn = make_logger(name, "warn");
+       local log_error = make_logger(name, "error");
+
+       --name = nil; -- While this line is not commented, will automatically fill in file/line number info
+       local namelen = #name;
+       return function (level, message, ...)
+                       if level == "debug" then
+                               return log_debug(message, ...);
+                       elseif level == "info" then
+                               return log_info(message, ...);
+                       elseif level == "warn" then
+                               return log_warn(message, ...);
+                       elseif level == "error" then
+                               return log_error(message, ...);
                        end
                end
-               
-               if not log_this then return function () end end
+end
+
+function make_logger(source_name, level)
+       local level_handlers = level_sinks[level];
+       if not level_handlers then
+               level_handlers = {};
+               level_sinks[level] = level_handlers;
        end
+
+       local source_handlers = name_sinks[source_name];
        
-       --name = nil; -- While this line is not commented, will automatically fill in file/line number info
-       local namelen = #name;
-       return  function (level, message, ...)
-                               if outfunction then return outfunction(name, level, message, ...); end
-                               
-                               sourcewidth = math_max(#name+2, sourcewidth);
-                               if ... then 
-                                       io_write(name, rep(" ", sourcewidth-namelen), getstring(logstyles[level], level), "\t", format(message, ...), "\n");
-                               else
-                                       io_write(name, rep(" ", sourcewidth-namelen), getstring(logstyles[level], level), "\t", message, "\n");
+       local logger = function (message, ...)
+               if source_handlers then
+                       for i = 1,#source_handlers do
+                               if source_handlers[i](source_name, level, message, ...) == false then
+                                       return;
                                end
                        end
+               end
+               
+               for i = 1,#level_handlers do
+                       level_handlers[i](source_name, level, message, ...);
+               end
+       end
+
+       return logger;
+end
+
+function reset()
+       for k in pairs(name_sinks) do name_sinks[k] = nil; end
+       for level, handler_list in pairs(level_sinks) do
+               -- Clear all handlers for this level
+               for i = 1, #handler_list do
+                       handler_list[i] = nil;
+               end
+       end
+       for k in pairs(name_patterns) do name_patterns[k] = nil; end
 end
 
-function setwriter(f)
-       local old_func = outfunction;
-       if not f then outfunction = nil; return true, old_func; end
-       local ok, ret = pcall(f, "logger", "info", "Switched logging output successfully");
-       if ok then
-               outfunction = f;
-               ret = old_func;
+function add_level_sink(level, sink_function)
+       if not level_sinks[level] then
+               level_sinks[level] = { sink_function };
+       else
+               level_sinks[level][#level_sinks[level] + 1 ] = sink_function;
        end
-       return ok, ret;
 end
 
+function add_name_sink(name, sink_function, exclusive)
+       if not name_sinks[name] then
+               name_sinks[name] = { sink_function };
+       else
+               name_sinks[name][#name_sinks[name] + 1] = sink_function;
+       end
+end
+
+function add_name_pattern_sink(name_pattern, sink_function, exclusive)
+       if not name_patterns[name_pattern] then
+               name_patterns[name_pattern] = { sink_function };
+       else
+               name_patterns[name_pattern][#name_patterns[name_pattern] + 1] = sink_function;
+       end
+end
+
+_M.new = make_logger;
+
 return _M;