Comparison

core/statsmanager.lua @ 7533:4ef37ac69562

statsmanager: Refactor to simplify logic. Notably renames 'statistics_provider' to 'statistics', and external libs now just begin with ':'
author Matthew Wild <mwild1@gmail.com>
date Fri, 29 Jul 2016 13:20:02 +0100
parent 7524:b6f32bb3b584
child 7664:4f145a9f1477
comparison
equal deleted inserted replaced
7531:2db68d1a6eeb 7533:4ef37ac69562
2 local config = require "core.configmanager"; 2 local config = require "core.configmanager";
3 local log = require "util.logger".init("stats"); 3 local log = require "util.logger".init("stats");
4 local timer = require "util.timer"; 4 local timer = require "util.timer";
5 local fire_event = prosody.events.fire_event; 5 local fire_event = prosody.events.fire_event;
6 6
7 local stats_config = config.get("*", "statistics_interval"); 7 local stats_interval_config = config.get("*", "statistics_interval");
8 local stats_interval = tonumber(stats_config); 8 local stats_interval = tonumber(stats_interval_config);
9 if stats_config and not stats_interval then 9 if stats_config and not stats_interval then
10 log("error", "Invalid 'statistics_interval' setting, statistics will be disabled"); 10 log("error", "Invalid 'statistics_interval' setting, statistics will be disabled");
11 end 11 end
12 12
13 local stats_provider_config = config.get("*", "statistics_provider"); 13 local stats_provider_name;
14 local stats_provider = stats_provider_config or "internal"; 14 local stats_provider_config = config.get("*", "statistics");
15 local stats_provider = stats_provider_config;
16
17 if not stats_provider and stats_interval then
18 stats_provider = "internal";
19 elseif stats_provider and not stats_interval then
20 stats_interval = 60;
21 end
15 22
16 local builtin_providers = { 23 local builtin_providers = {
17 internal = "util.statistics"; 24 internal = "util.statistics";
18 statsd = "util.statsd"; 25 statsd = "util.statsd";
19 }; 26 };
20 27
21 if stats_provider:match("^library:") then 28
22 stats_provider = stats_provider:match(":(.+)$"); 29 local stats, stats_err = false, nil;
23 else 30
24 stats_provider = builtin_providers[stats_provider]; 31 if stats_provider then
25 if not stats_provider then 32 if stats_provider:sub(1,1) == ":" then
26 log("error", "Unrecognized built-in statistics provider '%s', using internal instead", stats_provider_config); 33 stats_provider = stats_provider:sub(2);
27 stats_provider = builtin_providers["internal"]; 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);
40 end
41 end
42
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;
46 else
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;
28 end 50 end
29 end 51 end
30 52
31 local have_stats_provider, stats_lib = pcall(require, stats_provider); 53 if stats == nil then
32
33 local stats, stats_err;
34
35 if not have_stats_provider then
36 stats, stats_err = nil, stats_lib;
37 else
38 local stats_config = config.get("*", "statistics_config");
39 stats, stats_err = stats_lib.new(stats_config);
40 end
41
42 if not stats then
43 log("error", "Error loading statistics provider '%s': %s", stats_provider, stats_err); 54 log("error", "Error loading statistics provider '%s': %s", stats_provider, stats_err);
44 end 55 end
45 56
46 local measure, collect; 57 local measure, collect;
47 local latest_stats = {}; 58 local latest_stats = {};
51 if stats then 62 if stats then
52 function measure(type, name) 63 function measure(type, name)
53 local f = assert(stats[type], "unknown stat type: "..type); 64 local f = assert(stats[type], "unknown stat type: "..type);
54 return f(name); 65 return f(name);
55 end 66 end
67
68 if stats_interval then
69 log("debug", "Statistics enabled using %s provider, collecting every %d seconds", stats_provider_name, stats_interval);
70
71 local mark_collection_start = measure("times", "stats.collection");
72 local mark_processing_start = measure("times", "stats.processing");
73
74 function collect()
75 local mark_collection_done = mark_collection_start();
76 fire_event("stats-update");
77 mark_collection_done();
78
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;
87 end
88 if extra then
89 stats_extra[stat_name] = extra;
90 end
91 end
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();
95 end
96 return stats_interval;
97 end
98 timer.add_task(stats_interval, collect);
99 prosody.events.add_handler("server-started", function () collect() end, -1);
100 else
101 log("debug", "Statistics enabled using %s provider, collection is disabled", stats_provider_name);
102 end
103 else
104 log("debug", "Statistics disabled");
105 function measure() return measure; end
56 end 106 end
57 107
58 if stats_interval then
59 log("debug", "Statistics collection is enabled every %d seconds", stats_interval);
60
61 local mark_collection_start = measure("times", "stats.collection");
62 local mark_processing_start = measure("times", "stats.processing");
63
64 function collect()
65 local mark_collection_done = mark_collection_start();
66 fire_event("stats-update");
67 mark_collection_done();
68
69 if stats.get_stats then
70 changed_stats, stats_extra = {}, {};
71 for stat_name, getter in pairs(stats.get_stats()) do
72 local type, value, extra = getter();
73 local old_value = latest_stats[stat_name];
74 latest_stats[stat_name] = value;
75 if value ~= old_value then
76 changed_stats[stat_name] = value;
77 end
78 if extra then
79 stats_extra[stat_name] = extra;
80 end
81 end
82 local mark_processing_done = mark_processing_start();
83 fire_event("stats-updated", { stats = latest_stats, changed_stats = changed_stats, stats_extra = stats_extra });
84 mark_processing_done();
85 end
86 return stats_interval;
87 end
88 timer.add_task(stats_interval, collect);
89 prosody.events.add_handler("server-started", function () collect() end, -1);
90 end
91
92 if not stats_interval and stats_provider == "util.statistics" then
93 log("debug", "Statistics collection is disabled");
94 -- nop
95 function measure()
96 return measure;
97 end
98 function collect()
99 end
100 end
101 108
102 return { 109 return {
103 measure = measure; 110 measure = measure;
104 get_stats = function () 111 get_stats = function ()
105 return latest_stats, changed_stats, stats_extra; 112 return latest_stats, changed_stats, stats_extra;