util/logger.lua

1
-- Prosody IM
2
-- Copyright (C) 2008-2010 Matthew Wild
3
-- Copyright (C) 2008-2010 Waqas Hussain
4
-- 
5
-- This project is MIT/X11 licensed. Please see the
6
-- COPYING file in the source package for more information.
7
--
8
 
9
local pcall = pcall;
10
 
11
--local log_sources = config.get("*", "core", "log_sources");
12
 
13
local find = string.find;
14
local ipairs, pairs, setmetatable = ipairs, pairs, setmetatable;
15
 
16
module "logger"
17
 
18
local name_sinks, level_sinks = {}, {};
19
local name_patterns = {};
20
 
21
-- Weak-keyed so that loggers are collected
22
local modify_hooks = setmetatable({}, { __mode = "k" });
23
 
24
local make_logger;
25
local outfunction = nil;
26
 
27
function init(name)
28
	if log_sources then
29
		local log_this = false;
30
		for _, source in ipairs(log_sources) do
31
			if find(name, source) then 
32
				log_this = true;
33
				break;
34
			end
35
		end
36
		
37
		if not log_this then return function () end end
38
	end
39
	
40
	local log_debug = make_logger(name, "debug");
41
	local log_info = make_logger(name, "info");
42
	local log_warn = make_logger(name, "warn");
43
	local log_error = make_logger(name, "error");
44
 
45
	--name = nil; -- While this line is not commented, will automatically fill in file/line number info
46
	local namelen = #name;
47
	return function (level, message, ...)
48
			if outfunction then return outfunction(name, level, message, ...); end
49
			
50
			if level == "debug" then
51
				return log_debug(message, ...);
52
			elseif level == "info" then
53
				return log_info(message, ...);
54
			elseif level == "warn" then
55
				return log_warn(message, ...);
56
			elseif level == "error" then
57
				return log_error(message, ...);
58
			end
59
		end
60
end
61
 
62
function make_logger(source_name, level)
63
	local level_handlers = level_sinks[level];
64
	if not level_handlers then
65
		level_handlers = {};
66
		level_sinks[level] = level_handlers;
67
	end
68
 
69
	local source_handlers = name_sinks[source_name];
70
	
71
	-- All your premature optimisation is belong to me!
72
	local num_level_handlers, num_source_handlers = #level_handlers, source_handlers and #source_handlers;
73
	
74
	local logger = function (message, ...)
75
		if source_handlers then
76
			for i = 1,num_source_handlers do
77
				if source_handlers[i](source_name, level, message, ...) == false then
78
					return;
79
				end
80
			end
81
		end
82
		
83
		for i = 1,num_level_handlers do
84
			level_handlers[i](source_name, level, message, ...);
85
		end
86
	end
87
 
88
	-- To make sure our cached lengths stay in sync with reality
89
	modify_hooks[logger] = function () num_level_handlers, num_source_handlers = #level_handlers, source_handlers and #source_handlers; end; 
90
	
91
	return logger;
92
end
93
 
94
function setwriter(f)
95
	local old_func = outfunction;
96
	if not f then outfunction = nil; return true, old_func; end
97
	local ok, ret = pcall(f, "logger", "info", "Switched logging output successfully");
98
	if ok then
99
		outfunction = f;
100
		ret = old_func;
101
	end
102
	return ok, ret;
103
end
104
 
105
function reset()
106
	for k in pairs(name_sinks) do name_sinks[k] = nil; end
107
	for level, handler_list in pairs(level_sinks) do
108
		-- Clear all handlers for this level
109
		for i = 1, #handler_list do
110
			handler_list[i] = nil;
111
		end
112
	end
113
	for k in pairs(name_patterns) do name_patterns[k] = nil; end
114
 
115
	for _, modify_hook in pairs(modify_hooks) do
116
		modify_hook();
117
	end
118
end
119
 
120
function add_level_sink(level, sink_function)
121
	if not level_sinks[level] then
122
		level_sinks[level] = { sink_function };
123
	else
124
		level_sinks[level][#level_sinks[level] + 1 ] = sink_function;
125
	end
126
	
127
	for _, modify_hook in pairs(modify_hooks) do
128
		modify_hook();
129
	end
130
end
131
 
132
function add_name_sink(name, sink_function, exclusive)
133
	if not name_sinks[name] then
134
		name_sinks[name] = { sink_function };
135
	else
136
		name_sinks[name][#name_sinks[name] + 1] = sink_function;
137
	end
138
	
139
	for _, modify_hook in pairs(modify_hooks) do
140
		modify_hook();
141
	end
142
end
143
 
144
function add_name_pattern_sink(name_pattern, sink_function, exclusive)
145
	if not name_patterns[name_pattern] then
146
		name_patterns[name_pattern] = { sink_function };
147
	else
148
		name_patterns[name_pattern][#name_patterns[name_pattern] + 1] = sink_function;
149
	end
150
end
151
 
152
_M.new = make_logger;
153
 
154
return _M;