Internal Logger Improvement Plan
This document describes the improvements made to the internal logger and the plan for consistent use across services.
Implemented (current)
1. Per-user index (userId index)
- Write path: When a log entry has
userIdset, the internal cache service also updates a per-shard user index: keyinternal:userindex:{userId}on the same shard, value array of{ id, timestamp }sorted newest first. - Read path: When
getLogs({ userId, ... })is called, the multi-shard reader uses the user index instead of the global index: it readsinternal:userindex:{userId}from each shard. Only that user’s log IDs are scanned, so listing is much faster and bounded.
2. Cursor-based pagination
- No offset/page: The logs API uses cursor-based pagination only.
- Route:
GET /me/security/logs?limit=100&cursor=...&level=...&category=...(cursor optional). - Response:
{ data: InternalLogEntry[], pagination: { limit, nextCursor?, hasMore } }. - Internal:
InternalLogFiltershascursor?: string;getLogs()returnsInternalLogListResult { entries, nextCursor?, hasMore }. The multi-shard reader supportscursor(formattimestamp:id) and returnsnextCursorwhen there are more results.
3. Early exit when limit reached
- When reading from shards, the multi-shard reader stops requesting more shards once
allEntries.length >= limit, so we don’t over-fetch.
4. Services using internalLogger with userId
- Auth login: Already logs with userId (suspicious, warning, info).
- Auth register:
logAuthEvent('register_success', userId, ...). - Auth logout:
logAuthEvent('logout_success', session.userId, ...),logSecurityEventfor failures with userId. - Auth profile:
logUserEvent,logSecurityEventwith userId. - Auth verify:
logSecurityEvent('auth_verification_failed', ...)andlogSystemEvent('auth_verification_error', ...)on verification failure. - Me/avatar:
logUserEventwith userId on upload/delete failures. - Maintenance core:
logMaintenanceandlogSuspicious(logSecurityEvent-style) with userId for maintenance and security events. - InternalLoggerService exposes:
logAuthEvent,logSecurityEvent,logSystemEvent,logUserEvent,logMaintenance, pluswarning/error/suspicious/infowith optional userId/ipAddress.
Types and locations
- Cache types:
InternalLogEntry,InternalLogFilters,InternalLogListResultinsrc/types/cache/internal.ts. - User logs types:
UserLogsListOptions,UserLogsListResultinsrc/types/me/logs.ts(cursor-based:cursor,nextCursor,hasMore; no page/total). - Internal cache:
apps/worker/src/lib/services/cache/internal/index.ts(write: global index + user index when userId present; getLogs returns list result with cursor). - Multi-shard reader:
apps/worker/src/lib/services/cache/multi-shard-reader/index.ts(supportsindexKeySuffixfor user index, cursor, limit, early exit). - User logs service:
apps/worker/src/lib/services/me/logs/index.ts(cursor-only, uses internal logger’s getLogs with userId). - Route:
GET /me/security/logsinapps/worker/src/routes/me/security.ts(query: limit, cursor, level, category).
Optional future work
- Cursor in response for admin/system logs: When implementing
GET /system/internal/logs, use the same cursor-based API andInternalLogListResult. - More services: Ensure 2FA, secure-action, password reset, session revoke, user management (admin actions), and API/rate-limit paths log failures and important events with userId where applicable (see user-security-logs.md “Where else to use the internal logger”).
References
- User Security Logs Implementation — list implementation, filtering, who writes with userId.
- STEPS.md — user logs vs internal logs, phase plan.