-- 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 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 ;
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 )
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
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 ;