feat(services): add log and login/session services - #982
Conversation
Injects LogTailReader, LoginStats, ActivityRate, and ActiveConnections — added in #982 — into AdminSettings and passes their data to the template params, making the services active instead of dead code. Extracted from #977. Co-Authored-By: Frank Karlitschek <karlitschek@users.noreply.github.com> AI-assisted: Claude Code (claude-sonnet-4-6) Signed-off-by: Christoph Wurst <1374172+ChristophWurst@users.noreply.github.com>
7684654 to
b066758
Compare
Adds four read-only service classes used by the upcoming admin
dashboard cards. None are wired into existing controllers yet, so
this change is a pure addition with no behavior change.
* LogTailReader - last N WARN/ERROR entries from the JSON log
(no shell, line-bounded)
* LoginStats - bruteforce attempt counters and the top
offending IPs over recent windows
* ActivityRate - oc_activity row counts over the last hour /
day / week
* ActiveConnections - session counts derived from oc_authtoken
Signed-off-by: Frank Karlitschek <karlitschek@users.noreply.github.com>
Injects LogTailReader, LoginStats, ActivityRate, and ActiveConnections — added in #982 — into AdminSettings and passes their data to the template params, making the services active instead of dead code. Extracted from #977. Co-Authored-By: Frank Karlitschek <karlitschek@users.noreply.github.com> AI-assisted: Claude Code (claude-sonnet-4-6) Signed-off-by: Christoph Wurst <1374172+ChristophWurst@users.noreply.github.com>
b066758 to
b34e5c4
Compare
Injects LogTailReader, LoginStats, ActivityRate, and ActiveConnections — added in #982 — into AdminSettings and passes their data to the template params, making the services active instead of dead code. Extracted from #977. Co-Authored-By: Frank Karlitschek <karlitschek@users.noreply.github.com> AI-assisted: Claude Code (claude-sonnet-4-6) Signed-off-by: Christoph Wurst <1374172+ChristophWurst@users.noreply.github.com>
b34e5c4 to
8c232c6
Compare
Injects LogTailReader, LoginStats, ActivityRate, and ActiveConnections — added in #982 — into AdminSettings and passes their data to the template params, making the services active instead of dead code. Extracted from #977. Co-Authored-By: Frank Karlitschek <karlitschek@users.noreply.github.com> AI-assisted: Claude Code (claude-sonnet-4-6) Signed-off-by: Christoph Wurst <1374172+ChristophWurst@users.noreply.github.com>
8c232c6 to
9a7a730
Compare
Injects LogTailReader, LoginStats, ActivityRate, and ActiveConnections — added in #982 — into AdminSettings and passes their data to the template params, making the services active instead of dead code. Extracted from #977. Co-Authored-By: Frank Karlitschek <karlitschek@users.noreply.github.com> AI-assisted: Claude Code (claude-sonnet-4-6) Signed-off-by: Christoph Wurst <1374172+ChristophWurst@users.noreply.github.com>
9a7a730 to
28626fa
Compare
|
Activity, auth token and rate limiting are conceptually problematic. This creates an inter app dependency where this app accesses the persistence of another app directly. The technically sound way would be to go through a public API. Looking into these right now … |
|
Amended the original commit to fix the DCO and added class usage like it will be used later to avoid dead code. |
ChristophWurst
left a comment
There was a problem hiding this comment.
👍 functionality-wise
Needs decision conceptually
Injects LogTailReader, LoginStats, ActivityRate, and ActiveConnections — added in #982 — into AdminSettings and passes their data to the template params, making the services active instead of dead code. Extracted from #977. Co-Authored-By: Frank Karlitschek <karlitschek@users.noreply.github.com> AI-assisted: Claude Code (claude-sonnet-4-6) Signed-off-by: Christoph Wurst <1374172+ChristophWurst@users.noreply.github.com>
28626fa to
7fbf7cc
Compare
Injects LogTailReader, LoginStats, ActivityRate, and ActiveConnections — added in #982 — into AdminSettings and passes their data to the template params, making the services active instead of dead code. Extracted from #977. Co-Authored-By: Frank Karlitschek <karlitschek@users.noreply.github.com> AI-assisted: Claude Code (claude-sonnet-4-6) Signed-off-by: Christoph Wurst <1374172+ChristophWurst@users.noreply.github.com>
e7fafb7 to
b48f36c
Compare
There was a problem hiding this comment.
Pull request overview
Adds four new read-only “metrics” services to support upcoming admin UI cards (log tail, brute force/login stats, activity rate, and active connections), along with tests, and wires them into the admin settings template parameters.
Changes:
- Added service classes:
LogTailReader,LoginStats,ActivityRate, andActiveConnections. - Integrated the new services into
AdminSettings::getForm()response parameters. - Added PHPUnit coverage for the new services and updated the Psalm baseline for DI/unused-method noise.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/psalm-baseline.xml | Suppresses Psalm “PossiblyUnusedMethod::__construct” for the newly added services. |
| tests/lib/LogTailReaderTest.php | Unit tests for log tail availability, filtering, limits, and truncation. |
| tests/lib/LoginStatsTest.php | DB tests for bruteforce attempt counts and top IP aggregation. |
| tests/lib/ActivityRateTest.php | DB tests for activity counts over time windows and top-actions shape. |
| tests/lib/ActiveConnectionsTest.php | DB tests for auth token–based active connection/session counts. |
| lib/Settings/AdminSettings.php | Injects the new services and adds their results to the admin settings template params. |
| lib/LogTailReader.php | Implements safe log tail reading from file-based JSON log entries. |
| lib/LoginStats.php | Implements bruteforce attempt counters and top offending IP queries. |
| lib/ActivityRate.php | Implements activity table counting over multiple time windows plus top-actions query. |
| lib/ActiveConnections.php | Implements auth token counting over time windows and by token type. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| $qb->select('subjectparams', 'type') | ||
| ->selectAlias($qb->func()->count('activity_id'), 'count') | ||
| ->from('activity') | ||
| ->where($qb->expr()->gte('timestamp', $qb->createNamedParameter(time() - 86400))) | ||
| ->groupBy('type', 'subjectparams') |
| 'slowestJobs' => $this->slowestJobs->getSlowestJobs(), | ||
| 'logTail' => $this->logTailReader->recentErrors(), | ||
| 'loginStats' => $this->loginStats->getStats(), | ||
| 'activityRate' => $this->activityRate->getActivityRate(), | ||
| 'activeConnections' => $this->activeConnections->getActiveConnections(), |
| private function countAttempts(?int $sinceTimestamp = null): int { | ||
| $qb = $this->db->getQueryBuilder(); | ||
| $qb->select($qb->func()->count('id'))->from('bruteforce_attempts'); | ||
| if ($sinceTimestamp !== null) { | ||
| $qb->where($qb->expr()->gte('occurred', $qb->createNamedParameter($sinceTimestamp))); | ||
| } |
Adds four read-only service classes used by the upcoming admin dashboard cards. None are wired into existing controllers yet, so this change is a pure addition with no behavior change.
(no shell, line-bounded)
offending IPs over recent windows
day / week