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
|
local config = require "core.configmanager";
local log = require "util.logger".init("stats");
local timer = require "util.timer";
local fire_event = prosody.events.fire_event;
local stats_interval_config = config.get("*", "statistics_interval");
local stats_interval = tonumber(stats_interval_config);
if stats_interval_config and not stats_interval then
log("error", "Invalid 'statistics_interval' setting, statistics will be disabled");
end
local stats_provider_name;
local stats_provider_config = config.get("*", "statistics");
local stats_provider = stats_provider_config;
if not stats_provider and stats_interval then
stats_provider = "internal";
elseif stats_provider and not stats_interval then
stats_interval = 60;
end
local builtin_providers = {
internal = "util.statistics";
statsd = "util.statsd";
};
local stats, stats_err = false, nil;
if stats_provider then
if stats_provider:sub(1,1) == ":" then
stats_provider = stats_provider:sub(2);
stats_provider_name = "external "..stats_provider;
elseif stats_provider then
stats_provider_name = "built-in "..stats_provider;
stats_provider = builtin_providers[stats_provider];
if not stats_provider then
log("error", "Unrecognized statistics provider '%s', statistics will be disabled", stats_provider_config);
end
end
local have_stats_provider, stats_lib = pcall(require, stats_provider);
if not have_stats_provider then
stats, stats_err = nil, stats_lib;
else
local stats_config = config.get("*", "statistics_config");
stats, stats_err = stats_lib.new(stats_config);
stats_provider_name = stats_lib._NAME or stats_provider_name;
end
end
if stats == nil then
log("error", "Error loading statistics provider '%s': %s", stats_provider, stats_err);
end
local measure, collect;
local latest_stats = {};
local changed_stats = {};
local stats_extra = {};
if stats then
function measure(type, name, conf)
local f = assert(stats[type], "unknown stat type: "..type);
return f(name, conf);
end
if stats_interval then
log("debug", "Statistics enabled using %s provider, collecting every %d seconds", stats_provider_name, stats_interval);
local mark_collection_start = measure("times", "stats.collection");
local mark_processing_start = measure("times", "stats.processing");
function collect()
local mark_collection_done = mark_collection_start();
fire_event("stats-update");
mark_collection_done();
if stats.get_stats then
local mark_processing_done = mark_processing_start();
changed_stats, stats_extra = {}, {};
for stat_name, getter in pairs(stats.get_stats()) do
-- luacheck: ignore 211/type
local type, value, extra = getter();
local old_value = latest_stats[stat_name];
latest_stats[stat_name] = value;
if value ~= old_value then
changed_stats[stat_name] = value;
end
if extra then
stats_extra[stat_name] = extra;
end
end
fire_event("stats-updated", { stats = latest_stats, changed_stats = changed_stats, stats_extra = stats_extra });
mark_processing_done();
end
return stats_interval;
end
timer.add_task(stats_interval, collect);
prosody.events.add_handler("server-started", function () collect() end, -1);
prosody.events.add_handler("server-stopped", function () collect() end, -1);
else
log("debug", "Statistics enabled using %s provider, collection is disabled", stats_provider_name);
end
else
log("debug", "Statistics disabled");
function measure() return measure; end
end
return {
measure = measure;
get_stats = function ()
return latest_stats, changed_stats, stats_extra;
end;
get = function (name)
return latest_stats[name], stats_extra[name];
end;
};
|