aboutsummaryrefslogtreecommitdiffstats
path: root/util/logger.lua
blob: 1a2985b414e8412f83f5d7393d8fae3d6a5ad0fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
-- Prosody IM v0.4
-- 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;

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