Changeset

4774:1132f2888cd2

mod_measure_active_users: Calculate active user counts over fixed time periods
author Matthew Wild <mwild1@gmail.com>
date Wed, 17 Nov 2021 13:35:00 +0000
parents 4773:eb63890ae8fc
children 4775:fd90925dc239
files mod_measure_active_users/README.md mod_measure_active_users/mod_measure_active_users.lua
diffstat 2 files changed, 87 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_measure_active_users/README.md	Wed Nov 17 13:35:00 2021 +0000
@@ -0,0 +1,40 @@
+---
+labels:
+- 'Stage-Alpha'
+summary: 'Measure number of daily, weekly and monthly active users'
+...
+
+Introduction
+============
+
+This module calculates the number of daily, weekly and monthly active users -
+often abbreviated as DAU, WAU and MAU.
+
+These metrics are more accurate for determining how many people are actually
+using a service. For example simply counting registered accounts will typically
+include many dormant accounts that aren't really being used. Many servers also
+track the number of connected users. This is a useful metric for many purposes,
+but it is generally lower than the actual number of users - because some users
+may only connect at certain times of day.
+
+The module defines "activity" as any login/logout event during the time period,
+and for this it depends on mod_lastlog2 being loaded (it reads the data stored
+by mod_lastlog2). Each individual user is only counted once.
+
+"Daily" means any event within the past 24 hours, "weekly" means within the
+past 7 days, and "monthly" means within the past 30 days.
+
+Details
+=======
+
+The user count is calculated shortly after startup, and then recalculated
+hourly after that.
+
+Metrics are exported using Prosody's built-in statistics API.
+
+There is no configuration for this module.
+
+Compatibility
+=============
+
+Requires Prosody 0.11 or later with mod_lastlog2 enabled.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_measure_active_users/mod_measure_active_users.lua	Wed Nov 17 13:35:00 2021 +0000
@@ -0,0 +1,47 @@
+local store = module:open_store("lastlog2");
+
+local measure_d1 = module:measure("active_users_1d", "amount");
+local measure_d7 = module:measure("active_users_7d", "amount");
+local measure_d30 = module:measure("active_users_30d", "amount");
+
+function update_calculations()
+	module:log("debug", "Calculating active users");
+	local host_user_sessions = prosody.hosts[module.host].sessions;
+	local active_d1, active_d7, active_d30 = 0, 0, 0;
+	local now = os.time();
+	for username in store:users() do
+		if host_user_sessions[username] then
+			-- Active now
+			active_d1, active_d7, active_d30 =
+				active_d1 + 1, active_d7 + 1, active_d30 + 1;
+		else
+			local lastlog_data = store:get(username);
+			if lastlog_data then
+				-- Due to server restarts/crashes/etc. some events
+				-- may not always get recorded, so we'll just take the
+				-- latest as a sign of last activity
+				local last_active = math.max(
+					lastlog_data.login and lastlog_data.login.timestamp or 0,
+					lastlog_data.logout and lastlog_data.logout.timestamp or 0
+				);
+				if now - last_active < 86400 then
+					active_d1 = active_d1 + 1;
+				end
+				if now - last_active < 86400*7 then
+					active_d7 = active_d7 + 1;
+				end
+				if now - last_active < 86400*30 then
+					active_d30 = active_d30 + 1;
+				end
+			end
+		end
+	end
+	module:log("debug", "Active users (took %ds): %d (24h), %d (7d), %d (30d)", os.time()-now, active_d1, active_d7, active_d30);
+	measure_d1(active_d1);
+	measure_d7(active_d7);
+	measure_d30(active_d30);
+
+	return 3600 + (300*math.random());
+end
+
+module:add_timer(15, update_calculations);