Merge 0.10 -> trunk
authorMatthew Wild <mwild1@gmail.com>
Wed, 27 Jul 2016 14:08:32 +0100
changeset 7526 3c40b972260e
parent 7521 829ebe806e82 (current diff)
parent 7525 ebf2e77ac8a7 (diff)
child 7528 bad62a7f461f
Merge 0.10 -> trunk
net/http.lua
--- a/core/statsmanager.lua	Sun Jul 24 17:36:53 2016 +0100
+++ b/core/statsmanager.lua	Wed Jul 27 14:08:32 2016 +0100
@@ -1,5 +1,4 @@
 
-local stats = require "util.statistics".new();
 local config = require "core.configmanager";
 local log = require "util.logger".init("stats");
 local timer = require "util.timer";
@@ -11,46 +10,87 @@
 	log("error", "Invalid 'statistics_interval' setting, statistics will be disabled");
 end
 
+local stats_provider_config = config.get("*", "statistics_provider");
+local stats_provider = stats_provider_config or "internal";
+
+local builtin_providers = {
+	internal = "util.statistics";
+	statsd = "util.statsd";
+};
+
+if stats_provider:match("^library:") then
+	stats_provider = stats_provider:match(":(.+)$");
+else
+	stats_provider = builtin_providers[stats_provider];
+	if not stats_provider then
+		log("error", "Unrecognized built-in statistics provider '%s', using internal instead", stats_provider_config);
+		stats_provider = builtin_providers["internal"];
+	end
+end
+
+local have_stats_provider, stats_lib = pcall(require, stats_provider);
+
+local stats, stats_err;
+
+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);
+end
+
+if not stats 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_interval then
-	log("debug", "Statistics collection is enabled every %d seconds", stats_interval);
+if stats then
 	function measure(type, name)
 		local f = assert(stats[type], "unknown stat type: "..type);
 		return f(name);
 	end
+end
 
-	local mark_collection_start = measure("times", "stats.collection");
-	local mark_processing_start = measure("times", "stats.processing");
+if stats_interval then
+	if stats.get_stats then
+		log("debug", "Statistics collection is enabled every %d seconds", 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");
-		changed_stats, stats_extra = {}, {};
-		for stat_name, getter in pairs(stats.get_stats()) do
-			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;
+		function collect()
+			local mark_collection_done = mark_collection_start();
+			fire_event("stats-update");
+			changed_stats, stats_extra = {}, {};
+			for stat_name, getter in pairs(stats.get_stats()) do
+				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
-			if extra then
-				stats_extra[stat_name] = extra;
-			end
+			mark_collection_done();
+			local mark_processing_done = mark_processing_start();
+			fire_event("stats-updated", { stats = latest_stats, changed_stats = changed_stats, stats_extra = stats_extra });
+			mark_processing_done();
+			return stats_interval;
 		end
-		mark_collection_done();
-		local mark_processing_done = mark_processing_start();
-		fire_event("stats-updated", { stats = latest_stats, changed_stats = changed_stats, stats_extra = stats_extra });
-		mark_processing_done();
-		return stats_interval;
+		timer.add_task(stats_interval, collect);
+		prosody.events.add_handler("server-started", function () collect() end, -1);
+	else
+		log("error", "statistics_interval specified, but the selected statistics_provider (%s) does not support statistics collection", stats_provider_config or "internal");
 	end
+end
 
-	timer.add_task(stats_interval, collect);
-	prosody.events.add_handler("server-started", function () collect() end, -1);
-else
+if not stats_interval and stats_provider == "util.statistics" then
 	log("debug", "Statistics collection is disabled");
 	-- nop
 	function measure()
@@ -62,7 +102,6 @@
 
 return {
 	measure = measure;
-	collect = collect;
 	get_stats = function ()
 		return latest_stats, changed_stats, stats_extra;
 	end;
--- a/net/http.lua	Sun Jul 24 17:36:53 2016 +0100
+++ b/net/http.lua	Wed Jul 27 14:08:32 2016 +0100
@@ -117,7 +117,7 @@
 local function handleerr(err) log("error", "Traceback[http]: %s", traceback(tostring(err), 2)); end
 local function log_if_failed(id, ret, ...)
 	if not ret then
-		log("error", "Request %s: error in callback: %s", id, tostring((...)));
+		log("error", "Request '%s': error in callback: %s", id, tostring((...)));
 	end
 	return ...;
 end
@@ -172,7 +172,7 @@
 		end
 	end
 
-	log("debug", "Making %s %s request %s to %s", req.scheme, method or "GET", req.id, (ex and ex.suppress_url and host_header) or u);
+	log("debug", "Making %s %s request '%s' to %s", req.scheme:upper(), method or "GET", req.id, (ex and ex.suppress_url and host_header) or u);
 
 	-- Attach to request object
 	req.method, req.headers, req.body = method, headers, body;
@@ -197,7 +197,7 @@
 	req.write = function (...) return req.handler:write(...); end
 
 	req.callback = function (content, code, request, response)
-		log("debug", "request %s: Calling callback, status %s", req.id, code or "---");
+		log("debug", "Request '%s': Calling callback, status %s", req.id, code or "---");
 		return log_if_failed(req.id, xpcall(function () return callback(content, code, request, response) end, handleerr));
 	end
 	req.reader = request_reader;
--- a/util-src/table.c	Sun Jul 24 17:36:53 2016 +0100
+++ b/util-src/table.c	Wed Jul 27 14:08:32 2016 +0100
@@ -6,9 +6,24 @@
 	return 1;
 }
 
+static int Lpack(lua_State* L) {
+	unsigned int n_args = lua_gettop(L);
+	lua_createtable(L, n_args, 1);
+	lua_insert(L, 1);
+	for(int arg = n_args; arg >= 1; arg--) {
+		lua_rawseti(L, 1, arg);
+	}
+	lua_pushinteger(L, n_args);
+	lua_setfield(L, -2, "n");
+	return 1;
+}
+
+
 int luaopen_util_table(lua_State* L) {
 	lua_newtable(L);
 	lua_pushcfunction(L, Lcreate_table);
 	lua_setfield(L, -2, "create");
+	lua_pushcfunction(L, Lpack);
+	lua_setfield(L, -2, "pack");
 	return 1;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/statsd.lua	Wed Jul 27 14:08:32 2016 +0100
@@ -0,0 +1,84 @@
+local socket = require "socket";
+
+local time = require "socket".gettime;
+
+local function new(config)
+	if not config or not config.statsd_server then
+		return nil, "No statsd server specified in the config, please see https://prosody.im/doc/statistics";
+	end
+
+	local sock = socket.udp();
+	sock:setpeername(config.statsd_server, config.statsd_port or 8125);
+
+	local prefix = (config.prefix or "prosody")..".";
+
+	local function send_metric(s)
+		return sock:send(prefix..s);
+	end
+
+	local function send_gauge(name, amount, relative)
+		local s_amount = tostring(amount);
+		if relative and amount > 0 then
+			s_amount = "+"..s_amount;
+		end
+		return send_metric(name..":"..s_amount.."|g");
+	end
+
+	local function send_counter(name, amount)
+		return send_metric(name..":"..tostring(amount).."|c");
+	end
+
+	local function send_duration(name, duration)
+		return send_metric(name..":"..tostring(duration).."|ms");
+	end
+
+	local function send_histogram_sample(name, sample)
+		return send_metric(name..":"..tostring(sample).."|h");
+	end
+
+	local methods;
+	methods = {
+		amount = function (name, initial)
+			if initial then
+				send_gauge(name, initial);
+			end
+			return function (new_v) send_gauge(name, new_v); end
+		end;
+		counter = function (name, initial)
+			return function (delta)
+				send_gauge(name, delta, true);
+			end;
+		end;
+		rate = function (name)
+			return function ()
+				send_counter(name, 1);
+			end;
+		end;
+		distribution = function (name, unit, type) --luacheck: ignore 212/unit 212/type
+			return function (value)
+				send_histogram_sample(name, value);
+			end;
+		end;
+		sizes = function (name)
+			name = name.."_size";
+			return function (value)
+				send_histogram_sample(name, value);
+			end;
+		end;
+		times = function (name)
+			return function ()
+				local start_time = time();
+				return function ()
+					local end_time = time();
+					local duration = end_time - start_time;
+					send_duration(name, duration*1000);
+				end
+			end;
+		end;
+	};
+	return methods;
+end
+
+return {
+	new = new;
+}