Watch
0
0
Fork
You've already forked hyperhive
0

matrix: report homeserver up, latency and database size through existing collectors

tuwunel 1.9.4 exports no metrics. The host collector gets an httpcheck
receiver on the gateway's /_matrix/client/versions (new
services.hyperhive.otel.httpChecks, declared by hive-matrix), and a timer in
the hive-matrix container pushes the database directory's size through the
forwarder's OTLP port, as the attic cache-size unit does. The size step
dereferences the state directory's symlink and pushes nothing for a result
under 4096 bytes.
This commit is contained in:
atlas 2026-11-05 01:24:22 +01:00 • committed by mara
commit bef9d401a4

View file

@ -153,6 +153,14 @@ let
# Loopback in the container's own netns, and distinct from the other service
# containers' forwarders all the same.
forwarderTelemetryPort = 8899;
# Loopback in the container's own netns: the forwarder's OTLP/HTTP metrics
# receiver, which the database-size exporter pushes to.
forwarderOtlpPort = 8906;
databaseSizeUnit = "hive-matrix-database-size";
databaseSizePush = import ./lib/database-size-push.nix { inherit lib; };
# nixpkgs' default `services.matrix-tuwunel.stateDirectory`, which is also
# the database directory under /var/lib.
stateName = "tuwunel";
# ── the swarm's own appservice ──────────────────────────────────────
#
@ -497,6 +505,13 @@ in
}
'';
# The collector requests the homeserver through the gateway: tuwunel
# exports no metrics and binds no TCP port, and `httpcheck` dials HTTP(S)
# only, so the container's own forwarder cannot reach the socket.
services.hyperhive.otel.httpChecks = lib.optional (
cfg.gatewayHost != null
) "https://${cfg.gatewayHost}/_matrix/client/versions";
# `server_name = gatewayHost`. `/_matrix/*` → tuwunel (CORS `*`, 50M
# body cap, 1h long-poll timeout). `/` serves fluffychat. nginx's
# longest-prefix rule puts `/_matrix/`
@ -883,6 +898,7 @@ in
clientId = forwarderClientId;
tokenUrl = "${toString autheliaUrl}/api/oidc/token";
telemetryPort = forwarderTelemetryPort;
otlpMetricsPort = forwarderOtlpPort;
store = {
package = deployCfg.bao.package;
addr = "https://${baoCfg.domain}:${toString baoCfg.port}";
@ -893,6 +909,61 @@ in
};
};
# The size of tuwunel's database directory, pushed to the forwarder.
# tuwunel exports no metrics of its own. It runs as tuwunel's dynamic
# user, shared by name, because the state directory is mode 0700;
# with tuwunel stopped the name gets another uid and the read fails.
systemd.services.${databaseSizeUnit} = lib.mkIf ctlActive {
description = "push the size of tuwunel's database directory to the swarm collector";
wants = [ "tuwunel.service" ];
after = [
"tuwunel.service"
"opentelemetry-collector.service"
];
path = [
pkgs.coreutils
pkgs.curl
];
serviceConfig = {
Type = "oneshot";
User = "tuwunel";
DynamicUser = true;
StateDirectory = stateName;
StateDirectoryMode = "0700";
SyslogIdentifier = databaseSizeUnit;
UMask = "0077";
CapabilityBoundingSet = [ "" ];
NoNewPrivileges = true;
PrivateDevices = true;
PrivateTmp = true;
ProtectSystem = "strict";
ProtectHome = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
RestrictRealtime = true;
LockPersonality = true;
SystemCallArchitectures = "native";
};
script = databaseSizePush {
dir = "/var/lib/${stateName}";
otlpPort = forwarderOtlpPort;
};
};
systemd.timers.${databaseSizeUnit} = lib.mkIf ctlActive {
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = "2min";
OnUnitActiveSec = "5min";
};
};
# Its own netns, so it keeps its own firewall; resolvconf stays on
# and serves `networking.nameservers` below.
services.hyperhive.swarmContainer = {