From f19598cd27986c19ff4fb84a4943b74def2e53e9 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 20 Dec 2014 21:34:59 +0100 Subject: mod_pep: Fire an event when an item is published --- plugins/mod_pep.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua index 752cd28c..a6916d1f 100644 --- a/plugins/mod_pep.lua +++ b/plugins/mod_pep.lua @@ -41,7 +41,8 @@ local function subscription_presence(user_bare, recipient) return is_contact_subscribed(username, host, recipient_bare); end -local function publish(session, node, id, item) +module:hook("pep-publish-item", function (event) + local session, node, id, item = event.session, event.node, event.id, event.item; item.attr.xmlns = nil; local disable = #item.tags ~= 1 or #item.tags[1] == 0; if #item.tags == 0 then item.name = "retract"; end @@ -72,7 +73,8 @@ local function publish(session, node, id, item) core_post_stanza(session, stanza); end end -end +end); + local function publish_all(user, recipient, session) local d = data[user]; local notify = recipients[user] and recipients[user][recipient]; @@ -172,7 +174,9 @@ module:hook("iq/bare/http://jabber.org/protocol/pubsub:pubsub", function(event) local id = payload.attr.id or "1"; payload.attr.id = id; session.send(st.reply(stanza)); - publish(session, node, id, st.clone(payload)); + module:fire_event("pep-publish-item", { + node = node, actor = session.jid, id = id, session = session, item = st.clone(payload); + }); return true; end end -- cgit v1.2.3 From fff3bce92dce1501846a3f8ee6b350375ed22c58 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 12 Jan 2015 15:10:37 +0100 Subject: util.hex: Pedantic optimization, 1 table lookup per byte instead of 3 function calls makes it go faster --- util/hex.lua | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/util/hex.lua b/util/hex.lua index b21ee17e..e41f4863 100644 --- a/util/hex.lua +++ b/util/hex.lua @@ -1,19 +1,25 @@ local s_char = string.char; +local s_format = string.format; +local s_gsub = string.gsub; -local function char_to_hex(c) - return ("%02x"):format(c:byte()) -end +local char_to_hex = {}; +local hex_to_char = {}; -local function hex_to_char(h) - return s_char(tonumber(h, 16)); +do + local char, hex; + for i = 0,255 do + char, hex = s_char(i), s_format("%02x", i); + char_to_hex[char] = hex; + hex_to_char[hex] = char; + end end local function to(s) - return s:gsub(".", char_to_hex); + return (s_gsub(s, ".", char_to_hex)); end local function from(s) - return s:gsub("..", hex_to_char); + return (s_gsub(s, "..", hex_to_char)); end return { to = to, from = from } -- cgit v1.2.3 From 89650879bbcdfa58b7c43d80e55886c7aa788497 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 16 Jan 2015 14:02:14 +0100 Subject: mod_carbons: Import XEP-0280 implementation from prosody-modules (sans compat with older versions of the protocol) --- plugins/mod_carbons.lua | 111 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 plugins/mod_carbons.lua diff --git a/plugins/mod_carbons.lua b/plugins/mod_carbons.lua new file mode 100644 index 00000000..51242809 --- /dev/null +++ b/plugins/mod_carbons.lua @@ -0,0 +1,111 @@ +-- XEP-0280: Message Carbons implementation for Prosody +-- Copyright (C) 2011 Kim Alvefur +-- +-- This file is MIT/X11 licensed. + +local st = require "util.stanza"; +local jid_bare = require "util.jid".bare; +local xmlns_carbons = "urn:xmpp:carbons:2"; +local xmlns_forward = "urn:xmpp:forward:0"; +local full_sessions, bare_sessions = full_sessions, bare_sessions; + +local function toggle_carbons(event) + local origin, stanza = event.origin, event.stanza; + local state = stanza.tags[1].name; + module:log("debug", "%s %sd carbons", origin.full_jid, state); + origin.want_carbons = state == "enable" and stanza.tags[1].attr.xmlns; + return origin.send(st.reply(stanza)); +end +module:hook("iq-set/self/"..xmlns_carbons..":disable", toggle_carbons); +module:hook("iq-set/self/"..xmlns_carbons..":enable", toggle_carbons); + +local function message_handler(event, c2s) + local origin, stanza = event.origin, event.stanza; + local orig_type = stanza.attr.type; + local orig_from = stanza.attr.from; + local orig_to = stanza.attr.to; + + if not (orig_type == nil + or orig_type == "normal" + or orig_type == "chat") then + return -- No carbons for messages of type error or headline + end + + -- Stanza sent by a local client + local bare_jid = jid_bare(orig_from); + local target_session = origin; + local top_priority = false; + local user_sessions = bare_sessions[bare_jid]; + + -- Stanza about to be delivered to a local client + if not c2s then + bare_jid = jid_bare(orig_to); + target_session = full_sessions[orig_to]; + user_sessions = bare_sessions[bare_jid]; + if not target_session and user_sessions then + -- The top resources will already receive this message per normal routing rules, + -- so we are going to skip them in order to avoid sending duplicated messages. + local top_resources = user_sessions.top_resources; + top_priority = top_resources and top_resources[1].priority + end + end + + if not user_sessions then + module:log("debug", "Skip carbons for offline user"); + return -- No use in sending carbons to an offline user + end + + if stanza:get_child("private", xmlns_carbons) then + if not c2s then + stanza:maptags(function(tag) + if not ( tag.attr.xmlns == xmlns_carbons and tag.name == "private" ) then + return tag; + end + end); + end + module:log("debug", "Message tagged private, ignoring"); + return + elseif stanza:get_child("no-copy", "urn:xmpp:hints") then + module:log("debug", "Message has no-copy hint, ignoring"); + return + elseif stanza:get_child("x", "http://jabber.org/protocol/muc#user") then + module:log("debug", "MUC PM, ignoring"); + return + end + + -- Create the carbon copy and wrap it as per the Stanza Forwarding XEP + local copy = st.clone(stanza); + copy.attr.xmlns = "jabber:client"; + local carbon = st.message{ from = bare_jid, type = orig_type, } + :tag(c2s and "sent" or "received", { xmlns = xmlns_carbons }) + :tag("forwarded", { xmlns = xmlns_forward }) + :add_child(copy):reset(); + + user_sessions = user_sessions and user_sessions.sessions; + for _, session in pairs(user_sessions) do + -- Carbons are sent to resources that have enabled it + if session.want_carbons + -- but not the resource that sent the message, or the one that it's directed to + and session ~= target_session + -- and isn't among the top resources that would receive the message per standard routing rules + and (c2s or session.priority ~= top_priority) then + carbon.attr.to = session.full_jid; + module:log("debug", "Sending carbon to %s", session.full_jid); + session.send(carbon); + end + end +end + +local function c2s_message_handler(event) + return message_handler(event, true) +end + +-- Stanzas sent by local clients +module:hook("pre-message/host", c2s_message_handler, 1); +module:hook("pre-message/bare", c2s_message_handler, 1); +module:hook("pre-message/full", c2s_message_handler, 1); +-- Stanzas to local clients +module:hook("message/bare", message_handler, 1); +module:hook("message/full", message_handler, 1); + +module:add_feature(xmlns_carbons); -- cgit v1.2.3 From 186f9ee295dbb4435e396e705674410194f28372 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 20 Jan 2015 11:29:38 +0000 Subject: certmanager: Make global variable access explicit --- core/certmanager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/certmanager.lua b/core/certmanager.lua index 7ad7b034..b2c358fe 100644 --- a/core/certmanager.lua +++ b/core/certmanager.lua @@ -8,7 +8,7 @@ local configmanager = require "core.configmanager"; local log = require "util.logger".init("certmanager"); -local ssl = ssl; +local ssl = _G.ssl; local ssl_newcontext = ssl and ssl.newcontext; local new_config = require"util.sslconfig".new; -- cgit v1.2.3 From 3e62ff58706798955799740543394cc2d3e5e6e6 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 20 Jan 2015 11:30:07 +0000 Subject: hostmanager: Remove unused import of util.uuid --- core/hostmanager.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/core/hostmanager.lua b/core/hostmanager.lua index d10ecd30..7f9d1610 100644 --- a/core/hostmanager.lua +++ b/core/hostmanager.lua @@ -13,7 +13,6 @@ local disco_items = require "util.multitable".new(); local NULL = {}; local jid_split = require "util.jid".split; -local uuid_gen = require "util.uuid".generate; local log = require "util.logger".init("hostmanager"); -- cgit v1.2.3 From 322aa3c9c3b64c9df4d12f57b784961fceb23452 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 20 Jan 2015 11:31:04 +0000 Subject: portmanager: Remove unused import of pairs() --- core/portmanager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/portmanager.lua b/core/portmanager.lua index bc2d4264..eab2412a 100644 --- a/core/portmanager.lua +++ b/core/portmanager.lua @@ -9,7 +9,7 @@ local set = require "util.set"; local table = table; local setmetatable, rawset, rawget = setmetatable, rawset, rawget; -local type, tonumber, tostring, ipairs, pairs = type, tonumber, tostring, ipairs, pairs; +local type, tonumber, tostring, ipairs = type, tonumber, tostring, ipairs; local prosody = prosody; local fire_event = prosody.events.fire_event; -- cgit v1.2.3 From 7ebf4fa4c28fb0cda37c4ce62100bb59f102d185 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 20 Jan 2015 11:31:30 +0000 Subject: rostermanager: Access bare_sessions through prosody.bare_sessions --- core/rostermanager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/rostermanager.lua b/core/rostermanager.lua index 5266afb5..8c7612b4 100644 --- a/core/rostermanager.lua +++ b/core/rostermanager.lua @@ -15,7 +15,7 @@ local pairs = pairs; local tostring = tostring; local hosts = hosts; -local bare_sessions = bare_sessions; +local bare_sessions = prosody.bare_sessions; local datamanager = require "util.datamanager" local um_user_exists = require "core.usermanager".user_exists; -- cgit v1.2.3 From 79dfda0f225e20597c97f5b22c2547ecd5a2b6ec Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 20 Jan 2015 11:31:58 +0000 Subject: sessionmanager: Access bare_session and full_sessions through 'prosody' --- core/sessionmanager.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/sessionmanager.lua b/core/sessionmanager.lua index 65e5156c..09920b7d 100644 --- a/core/sessionmanager.lua +++ b/core/sessionmanager.lua @@ -10,8 +10,8 @@ local tostring, setmetatable = tostring, setmetatable; local pairs, next= pairs, next; local hosts = hosts; -local full_sessions = full_sessions; -local bare_sessions = bare_sessions; +local full_sessions = prosody.full_sessions; +local bare_sessions = prosody.bare_sessions; local logger = require "util.logger"; local log = logger.init("sessionmanager"); -- cgit v1.2.3 From fc6578a114ec5cae2a4c33f1dd3f4e8f39557701 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 20 Jan 2015 11:32:14 +0000 Subject: storagemanager: Remove unused import of error() --- core/storagemanager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/storagemanager.lua b/core/storagemanager.lua index 5674ff32..ad31eb80 100644 --- a/core/storagemanager.lua +++ b/core/storagemanager.lua @@ -1,5 +1,5 @@ -local error, type, pairs = error, type, pairs; +local type, pairs = type, pairs; local setmetatable = setmetatable; local config = require "core.configmanager"; -- cgit v1.2.3 From 4554389fc92b39024a811315776a4a272dac115b Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 20 Jan 2015 12:31:32 +0000 Subject: util.statistics: New library for gathering various kinds of statistics --- util/statistics.lua | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 util/statistics.lua diff --git a/util/statistics.lua b/util/statistics.lua new file mode 100644 index 00000000..9d332053 --- /dev/null +++ b/util/statistics.lua @@ -0,0 +1,131 @@ +local t_sort = table.sort +local m_floor = math.floor; +local time = require "socket".gettime; + +local function nop_function() end + +local function percentile(arr, length, pc) + local n = pc/100 * (length + 1); + local k, d = m_floor(n), n%1; + if k == 0 then + return arr[1]; + elseif k >= length then + return arr[length]; + end + return arr[k] + d*(arr[k+1] - arr[k]); +end + +local function new_registry(config) + config = config or {}; + local duration_sample_interval = config.duration_sample_interval or 5; + local duration_max_samples = config.duration_max_stored_samples or 5000; + + local registry = {}; + local methods; + methods = { + amount = function (name, initial) + local v = initial or 0; + registry[name] = function () return "amount", v; end + return function (new_v) v = new_v; end + end; + counter = function (name, initial) + local v = initial or 0; + registry[name] = function () return "amount", v; end + return function (delta) + v = v + delta; + end; + end; + rate = function (name) + local since, n = time(), 0; + registry[name] = function () + local t = time(); + local stats = { + rate = n/(t-since); + count = n; + }; + since, n = t, 0; + return "rate", stats.rate, stats; + end; + return function () + n = n + 1; + end; + end; + duration = function (name) + local events, last_event = {}, 0; + local n_actual_events = 0; + local since = time(); + + registry[name] = function () + local n_stored_events = #events; + t_sort(events); + local sum = 0; + for i = 1, n_stored_events do + sum = sum + events[i]; + end + + local new_time = time(); + + local stats = { + samples = events; + sample_count = n_stored_events; + count = n_actual_events, + rate = n_actual_events/(new_time-since); + average = n_stored_events > 0 and sum/n_stored_events or 0, + min = events[1], + max = events[n_stored_events], + }; + + events, last_event = {}, 0; + n_actual_events = 0; + since = new_time; + + return "duration", stats.average, stats; + end; + + return function () + n_actual_events = n_actual_events + 1; + if n_actual_events%duration_sample_interval > 0 then + return nop_function; + end + + local start_time = time(); + return function () + local end_time = time(); + local duration = end_time - start_time; + last_event = (last_event%duration_max_samples) + 1; + events[last_event] = duration; + end + end; + end; + + get_stats = function () + return registry; + end; + }; + return methods; +end + +return { + new = new_registry; + get_histogram = function (duration, n_buckets) + n_buckets = n_buckets or 100; + local events, n_events = duration.samples, duration.sample_count; + if not (events and n_events) then + return nil, "not a valid duration stat"; + end + local histogram = {}; + + for i = 1, 100, 100/n_buckets do + histogram[i] = percentile(events, n_events, i); + end + return histogram; + end; + + get_percentile = function (duration, pc) + local events, n_events = duration.samples, duration.sample_count; + if not (events and n_events) then + return nil, "not a valid duration stat"; + end + return percentile(events, n_events, pc); + end; +} -- cgit v1.2.3 From a88d04d1c41f710bac967ddeb5558263ab73da53 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 20 Jan 2015 12:33:20 +0000 Subject: statsmanager, prosody: New core module and API for gathering statistics about the running server --- core/statsmanager.lua | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++ prosody | 1 + 2 files changed, 76 insertions(+) create mode 100644 core/statsmanager.lua diff --git a/core/statsmanager.lua b/core/statsmanager.lua new file mode 100644 index 00000000..83df6181 --- /dev/null +++ b/core/statsmanager.lua @@ -0,0 +1,75 @@ + +local stats = require "util.statistics".new(); +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_config = config.get("*", "statistics_interval"); +local stats_interval = tonumber(stats_config); +if stats_config and not stats_interval then + log("error", "Invalid 'statistics_interval' setting, statistics will be disabled"); +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); + function measure(type, name) + local f = assert(stats[type], "unknown stat type: "..type); + return f(name); + end + + local mark_collection_start = measure("duration", "stats.collection_time"); + local mark_processing_start = measure("duration", "stats.processing_time"); + + function collect() + local mark_collection_done = mark_collection_start(); + changed_stats, stats_extra = {}, {}; + for name, getter in pairs(stats.get_stats()) do + local type, value, extra = getter(); + local stat_name = name..":"..type; + 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 + print(stat_name, extra) + stats_extra[stat_name] = extra; + if type == "duration" then + local rate = extra.rate; + local rate_name = name..":rate"; + latest_stats[rate_name] = rate; + changed_stats[rate_name] = rate; + end + end + 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 + + timer.add_task(stats_interval, collect); +else + log("debug", "Statistics collection is disabled"); + -- nop + function measure() + return measure; + end + function collect() + end +end + +return { + measure = measure; + collect = collect; + get_stats = function () + return latest_stats, changed_stats, stats_extra; + end; +}; diff --git a/prosody b/prosody index e8f81d5d..e6a23d8e 100755 --- a/prosody +++ b/prosody @@ -292,6 +292,7 @@ function load_secondary_libraries() require "util.import" require "util.xmppstream" require "core.stanza_router" + require "core.statsmanager" require "core.hostmanager" require "core.portmanager" require "core.modulemanager" -- cgit v1.2.3 From 6790b2a0ba6b2b10ad327334296b48544e2c6553 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 21 Jan 2015 01:26:06 +0000 Subject: statsmanager, util.statistics: API changes, remove debugging --- core/statsmanager.lua | 14 ++-------- util/statistics.lua | 77 +++++++++++++++++++++++++++++++++++---------------- 2 files changed, 56 insertions(+), 35 deletions(-) diff --git a/core/statsmanager.lua b/core/statsmanager.lua index 83df6181..62d217ef 100644 --- a/core/statsmanager.lua +++ b/core/statsmanager.lua @@ -23,29 +23,21 @@ if stats_interval then return f(name); end - local mark_collection_start = measure("duration", "stats.collection_time"); - local mark_processing_start = measure("duration", "stats.processing_time"); + 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(); changed_stats, stats_extra = {}, {}; - for name, getter in pairs(stats.get_stats()) do + for stat_name, getter in pairs(stats.get_stats()) do local type, value, extra = getter(); - local stat_name = name..":"..type; 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 - print(stat_name, extra) stats_extra[stat_name] = extra; - if type == "duration" then - local rate = extra.rate; - local rate_name = name..":rate"; - latest_stats[rate_name] = rate; - changed_stats[rate_name] = rate; - end end end mark_collection_done(); diff --git a/util/statistics.lua b/util/statistics.lua index 9d332053..08c765ae 100644 --- a/util/statistics.lua +++ b/util/statistics.lua @@ -20,24 +20,45 @@ local function new_registry(config) local duration_sample_interval = config.duration_sample_interval or 5; local duration_max_samples = config.duration_max_stored_samples or 5000; + local function get_distribution_stats(events, n_actual_events, since, new_time, units) + local n_stored_events = #events; + t_sort(events); + local sum = 0; + for i = 1, n_stored_events do + sum = sum + events[i]; + end + + return { + samples = events; + sample_count = n_stored_events; + count = n_actual_events, + rate = n_actual_events/(new_time-since); + average = n_stored_events > 0 and sum/n_stored_events or 0, + min = events[1] or 0, + max = events[n_stored_events] or 0, + units = units, + }; + end + + local registry = {}; local methods; methods = { amount = function (name, initial) local v = initial or 0; - registry[name] = function () return "amount", v; end + registry[name..":amount"] = function () return "amount", v; end return function (new_v) v = new_v; end end; counter = function (name, initial) local v = initial or 0; - registry[name] = function () return "amount", v; end + registry[name..":amount"] = function () return "amount", v; end return function (delta) v = v + delta; end; end; rate = function (name) local since, n = time(), 0; - registry[name] = function () + registry[name..":rate"] = function () local t = time(); local stats = { rate = n/(t-since); @@ -50,35 +71,43 @@ local function new_registry(config) n = n + 1; end; end; - duration = function (name) + distribution = function (name, unit, type) + type = type or "distribution"; local events, last_event = {}, 0; local n_actual_events = 0; local since = time(); - registry[name] = function () - local n_stored_events = #events; - t_sort(events); - local sum = 0; - for i = 1, n_stored_events do - sum = sum + events[i]; - end - + registry[name..":"..type] = function () local new_time = time(); + local stats = get_distribution_stats(events, n_actual_events, since, new_time, unit); + events, last_event = {}, 0; + n_actual_events = 0; + since = new_time; + return type, stats.average, stats; + end; - local stats = { - samples = events; - sample_count = n_stored_events; - count = n_actual_events, - rate = n_actual_events/(new_time-since); - average = n_stored_events > 0 and sum/n_stored_events or 0, - min = events[1], - max = events[n_stored_events], - }; + return function (value) + n_actual_events = n_actual_events + 1; + if n_actual_events%duration_sample_interval > 0 then + last_event = (last_event%duration_max_samples) + 1; + events[last_event] = value; + end + end; + end; + sizes = function (name) + return methods.distribution(name, "bytes", "size"); + end; + times = function (name) + local events, last_event = {}, 0; + local n_actual_events = 0; + local since = time(); + registry[name..":duration"] = function () + local new_time = time(); + local stats = get_distribution_stats(events, n_actual_events, since, new_time, "seconds"); events, last_event = {}, 0; n_actual_events = 0; since = new_time; - return "duration", stats.average, stats; end; @@ -111,7 +140,7 @@ return { n_buckets = n_buckets or 100; local events, n_events = duration.samples, duration.sample_count; if not (events and n_events) then - return nil, "not a valid duration stat"; + return nil, "not a valid distribution stat"; end local histogram = {}; @@ -124,7 +153,7 @@ return { get_percentile = function (duration, pc) local events, n_events = duration.samples, duration.sample_count; if not (events and n_events) then - return nil, "not a valid duration stat"; + return nil, "not a valid distribution stat"; end return percentile(events, n_events, pc); end; -- cgit v1.2.3 From e0c0cffcc27601ec9e4dd3d6fcb556baa21f1e21 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 21 Jan 2015 01:28:12 +0000 Subject: moduleapi: Module API for statsmanager --- core/moduleapi.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/moduleapi.lua b/core/moduleapi.lua index c30a8936..e32c116a 100644 --- a/core/moduleapi.lua +++ b/core/moduleapi.lua @@ -14,6 +14,7 @@ local logger = require "util.logger"; local pluginloader = require "util.pluginloader"; local timer = require "util.timer"; local resolve_relative_path = require"util.paths".resolve_relative_path; +local measure = require "core.statsmanager".measure; local t_insert, t_remove, t_concat = table.insert, table.remove, table.concat; local error, setmetatable, type = error, setmetatable, type; @@ -370,6 +371,10 @@ function api:open_store(name, type) return require"core.storagemanager".open(self.host, name or self.name, type); end +function api:measure(name, type) + return measure(type, "/"..self.host.."/mod_"..self.name.."/"..name); +end + function api.init(mm) modulemanager = mm; return api; -- cgit v1.2.3