X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=util%2Flogger.lua;h=a73c7eec90c156903f06bb71a6288a62284868f9;hb=4899743c62b06d41dd6092fa3435bb64b2d9ce98;hp=3d672e942805272345486c6d94e49f8bbf90d395;hpb=6e71a4c6b4dad19c8ad6636f7503a1e5cb7079f4;p=prosody.git diff --git a/util/logger.lua b/util/logger.lua index 3d672e94..a73c7eec 100644 --- a/util/logger.lua +++ b/util/logger.lua @@ -1,23 +1,140 @@ +-- Prosody IM +-- Copyright (C) 2008-2009 Matthew Wild +-- Copyright (C) 2008-2009 Waqas Hussain +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- + +local pcall = pcall; + +local config = require "core.configmanager"; +local log_sources = config.get("*", "core", "log_sources"); + +local find = string.find; +local ipairs, pairs, setmetatable = ipairs, pairs, setmetatable; -local format = string.format; -local print = print; -local debug = debug; -local tostring = tostring; module "logger" +local name_sinks, level_sinks = {}, {}; +local name_patterns = {}; + +-- Weak-keyed so that loggers are collected +local modify_hooks = setmetatable({}, { __mode = "k" }); + +local make_logger; +local outfunction = nil; + function init(name) - name = nil; -- While this line is not commented, will automatically fill in file/line number info - return function (level, message, ...) - if not name then - local inf = debug.getinfo(2, 'Snl'); - level = level .. ","..tostring(inf.short_src):match("[^/]*$")..":"..inf.currentline; - end - if ... then - print(level, format(message, ...)); - else - print(level, message); + if log_sources then + local log_this = false; + for _, source in ipairs(log_sources) do + if find(name, source) then + log_this = true; + break; + end + end + + if not log_this then return function () end end + end + + 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 outfunction then return outfunction(name, level, message, ...); end + + 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 +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]; + + -- All your premature optimisation is belong to me! + local num_level_handlers, num_source_handlers = #level_handlers, source_handlers and #source_handlers; + + local logger = function (message, ...) + if source_handlers then + for i = 1,num_source_handlers do + if source_handlers[i](source_name, level, message, ...) == false then + return; end end + end + + for i = 1,num_level_handlers do + level_handlers[i](source_name, level, message, ...); + end + end + + -- To make sure our cached lengths stay in sync with reality + modify_hooks[logger] = function () num_level_handlers, num_source_handlers = #level_handlers, source_handlers and #source_handlers; end; + + return logger; +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; + end + return ok, ret; +end + +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 + + for _, modify_hook in pairs(modify_hooks) do + modify_hook(); + end end -return _M; \ No newline at end of file +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 + + for _, modify_hook in pairs(modify_hooks) do + modify_hook(); + 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;