2 local config
= require
"core.configmanager";
3 local log = require
"util.logger".init("stats");
4 local timer
= require
"util.timer";
5 local fire_event
= prosody
.events
.fire_event
;
7 local stats_interval_config
= config
.get("*", "statistics_interval");
8 local stats_interval
= tonumber(stats_interval_config
);
9 if stats_interval_config
and not stats_interval
then
10 log("error", "Invalid 'statistics_interval' setting, statistics will be disabled");
13 local stats_provider_name
;
14 local stats_provider_config
= config
.get("*", "statistics");
15 local stats_provider
= stats_provider_config
;
17 if not stats_provider
and stats_interval
then
18 stats_provider
= "internal";
19 elseif stats_provider
and not stats_interval
then
23 local builtin_providers
= {
24 internal
= "util.statistics";
25 statsd
= "util.statsd";
29 local stats
, stats_err
= false, nil;
31 if stats_provider
then
32 if stats_provider
:sub(1,1) == ":" then
33 stats_provider
= stats_provider
:sub(2);
34 stats_provider_name
= "external "..stats_provider
;
35 elseif stats_provider
then
36 stats_provider_name
= "built-in "..stats_provider
;
37 stats_provider
= builtin_providers
[stats_provider
];
38 if not stats_provider
then
39 log("error", "Unrecognized statistics provider '%s', statistics will be disabled", stats_provider_config
);
43 local have_stats_provider
, stats_lib
= pcall(require
, stats_provider
);
44 if not have_stats_provider
then
45 stats
, stats_err
= nil, stats_lib
;
47 local stats_config
= config
.get("*", "statistics_config");
48 stats
, stats_err
= stats_lib
.new(stats_config
);
49 stats_provider_name
= stats_lib
._NAME
or stats_provider_name
;
54 log("error", "Error loading statistics provider '%s': %s", stats_provider
, stats_err
);
57 local measure
, collect
;
58 local latest_stats
= {};
59 local changed_stats
= {};
60 local stats_extra
= {};
63 function measure(type, name
)
64 local f
= assert(stats
[type], "unknown stat type: "..type);
68 if stats_interval
then
69 log("debug", "Statistics enabled using %s provider, collecting every %d seconds", stats_provider_name
, stats_interval
);
71 local mark_collection_start
= measure("times", "stats.collection");
72 local mark_processing_start
= measure("times", "stats.processing");
75 local mark_collection_done
= mark_collection_start();
76 fire_event("stats-update");
77 mark_collection_done();
79 if stats
.get_stats
then
80 changed_stats
, stats_extra
= {}, {};
81 for stat_name
, getter
in pairs(stats
.get_stats()) do
82 local type, value
, extra
= getter();
83 local old_value
= latest_stats
[stat_name
];
84 latest_stats
[stat_name
] = value
;
85 if value
~= old_value
then
86 changed_stats
[stat_name
] = value
;
89 stats_extra
[stat_name
] = extra
;
92 local mark_processing_done
= mark_processing_start();
93 fire_event("stats-updated", { stats
= latest_stats
, changed_stats
= changed_stats
, stats_extra
= stats_extra
});
94 mark_processing_done();
96 return stats_interval
;
98 timer
.add_task(stats_interval
, collect
);
99 prosody
.events
.add_handler("server-started", function () collect() end, -1);
100 prosody
.events
.add_handler("server-stopped", function () collect() end, -1);
102 log("debug", "Statistics enabled using %s provider, collection is disabled", stats_provider_name
);
105 log("debug", "Statistics disabled");
106 function measure() return measure
; end
112 get_stats
= function ()
113 return latest_stats
, changed_stats
, stats_extra
;
115 get
= function (name
)
116 return latest_stats
[name
], stats_extra
[name
];