mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-02 20:30:10 +00:00
Implement centralized logging with RMABLogger
Replaces scattered console statements with a unified RMABLogger across backend API routes and services. Adds LOG_LEVEL-based filtering, job-aware database persistence, and context-based logging. Updates documentation to describe the new logging system and usage patterns. Also documents qBittorrent CSRF header fix
This commit is contained in:
@@ -55,6 +55,11 @@
|
||||
- **Scheduled/recurring jobs (cron)** → [backend/services/scheduler.md](backend/services/scheduler.md)
|
||||
- **Job types:** search, download monitor, organize, Plex scan, cleanup, retries
|
||||
|
||||
## Logging
|
||||
- **Centralized logging (RMABLogger)** → [backend/services/logging.md](backend/services/logging.md)
|
||||
- **LOG_LEVEL configuration** → [backend/services/logging.md](backend/services/logging.md)
|
||||
- **Job-aware database persistence** → [backend/services/logging.md](backend/services/logging.md)
|
||||
|
||||
## Frontend Components
|
||||
- **Component catalog (cards, badges, forms)** → [frontend/components.md](frontend/components.md)
|
||||
- **RequestCard, StatusBadge, ProgressBar** → [frontend/components.md](frontend/components.md)
|
||||
@@ -94,6 +99,7 @@
|
||||
**"OAuth redirects to localhost / PUBLIC_URL not working"** → [backend/services/environment.md](backend/services/environment.md)
|
||||
**"What environment variables do I need?"** → [backend/services/environment.md](backend/services/environment.md)
|
||||
**"How does chapter merging work?"** → [features/chapter-merging.md](features/chapter-merging.md)
|
||||
**"How does logging work?"** → [backend/services/logging.md](backend/services/logging.md)
|
||||
**"How does Audiobookshelf integration work?"** → [features/audiobookshelf-integration.md](features/audiobookshelf-integration.md) (PRD only, not implemented)
|
||||
**"How do I use OIDC/Authentik/Keycloak?"** → [features/audiobookshelf-integration.md](features/audiobookshelf-integration.md) (PRD only, not implemented)
|
||||
**"How does manual user registration work?"** → [features/audiobookshelf-integration.md](features/audiobookshelf-integration.md) (PRD only, not implemented)
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
# Centralized Logging (RMABLogger)
|
||||
|
||||
**Status:** Implemented | Unified logging with LOG_LEVEL filtering + job database persistence
|
||||
|
||||
## Overview
|
||||
|
||||
Single logging infrastructure for all backend services. Replaces scattered console statements with centralized logger that respects LOG_LEVEL env var and persists job-aware logs to database.
|
||||
|
||||
## Key Details
|
||||
|
||||
### Usage Patterns
|
||||
|
||||
**Standard logging (no job association):**
|
||||
```typescript
|
||||
import { RMABLogger } from '../utils/logger';
|
||||
|
||||
const logger = RMABLogger.create('ServiceName');
|
||||
logger.info('Operation started');
|
||||
logger.debug('Detailed info', { key: 'value' });
|
||||
logger.warn('Potential issue');
|
||||
logger.error('Failed operation', { error: err.message });
|
||||
```
|
||||
|
||||
**Job-aware logging (persists to database):**
|
||||
```typescript
|
||||
const logger = RMABLogger.forJob(jobId, 'ProcessorName');
|
||||
logger.info('Processing...'); // Logs to console AND database
|
||||
logger.debug('Debug info'); // Console only (never persisted)
|
||||
```
|
||||
|
||||
### LOG_LEVEL Configuration
|
||||
|
||||
| Value | Logs Shown |
|
||||
|-------|------------|
|
||||
| `debug` | All (debug + info + warn + error) |
|
||||
| `info` | Default (info + warn + error) |
|
||||
| `warn` | warn + error only |
|
||||
| `error` | error only |
|
||||
| `quiet` | None (DB logging still works for job-aware) |
|
||||
|
||||
### Output Format
|
||||
```
|
||||
[LEVEL] [Context] Message
|
||||
```
|
||||
|
||||
Example:
|
||||
```
|
||||
[INFO] [QBittorrent] Connected successfully
|
||||
[DEBUG] [SearchIndexers] Found 15 results
|
||||
[WARN] [MonitorDownload] Torrent stalled, retrying
|
||||
[ERROR] [OrganizeFiles] Failed to move file
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Factory Methods
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `RMABLogger.create(context)` | Standard logger for context namespace |
|
||||
| `RMABLogger.forJob(jobId, context)` | Job-aware logger with DB persistence |
|
||||
|
||||
### Log Methods
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `.debug(msg, metadata?)` | Verbose debugging (console only, never DB) |
|
||||
| `.info(msg, metadata?)` | Normal operations |
|
||||
| `.warn(msg, metadata?)` | Warnings |
|
||||
| `.error(msg, metadata?)` | Errors |
|
||||
|
||||
### Child Loggers
|
||||
|
||||
```typescript
|
||||
const logger = RMABLogger.create('Parent');
|
||||
const child = logger.child('SubContext');
|
||||
// Output: [INFO] [Parent.SubContext] Message
|
||||
```
|
||||
|
||||
## Database Persistence
|
||||
|
||||
Job-aware loggers persist to `job_events` table:
|
||||
- `jobId` - Associated job ID
|
||||
- `level` - info, warn, error (never debug)
|
||||
- `context` - Logger context
|
||||
- `message` - Log message
|
||||
- `metadata` - JSON metadata (optional)
|
||||
- `createdAt` - Timestamp
|
||||
|
||||
**Note:** Debug logs are NEVER persisted to keep job_events clean.
|
||||
|
||||
## Files
|
||||
|
||||
- **Core:** `src/lib/utils/logger.ts`
|
||||
- **Backward compat:** `src/lib/utils/job-logger.ts` (deprecated wrapper)
|
||||
|
||||
## Context Naming Conventions
|
||||
|
||||
| Component Type | Pattern | Example |
|
||||
|----------------|---------|---------|
|
||||
| Integration | Service name | `QBittorrent`, `Plex`, `Prowlarr` |
|
||||
| Processor | Job type | `SearchIndexers`, `MonitorDownload` |
|
||||
| API Route | `API.{resource}` | `API.Requests`, `API.Auth` |
|
||||
| Service | Service name | `ConfigService`, `JobQueue` |
|
||||
|
||||
## Migration Guide
|
||||
|
||||
**Before:**
|
||||
```typescript
|
||||
console.log('[ServiceName] Operation done');
|
||||
console.error('[ServiceName] Error:', error);
|
||||
if (process.env.LOG_LEVEL === 'debug') {
|
||||
console.log('Debug info');
|
||||
}
|
||||
```
|
||||
|
||||
**After:**
|
||||
```typescript
|
||||
import { RMABLogger } from '../utils/logger';
|
||||
const logger = RMABLogger.create('ServiceName');
|
||||
|
||||
logger.info('Operation done');
|
||||
logger.error('Error', { error: error.message });
|
||||
logger.debug('Debug info'); // Automatically filtered by LOG_LEVEL
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [Job Queue & Processors](jobs.md) - Background job system
|
||||
- [Scheduler](scheduler.md) - Recurring tasks
|
||||
@@ -176,6 +176,11 @@ type TorrentState = 'downloading' | 'uploading' | 'stalledDL' |
|
||||
- Enhanced error messages identifying SSL/TLS certificate issues with actionable guidance
|
||||
- Secure by default (SSL verification enabled), with clear security warnings when disabled
|
||||
- URL format: `https://qbt.domain.com:443/qbittorrent` fully supported
|
||||
**12. CSRF protection HTTP 401 errors** - qBittorrent v4.1.0+ has CSRF protection enabled by default, causing authentication failures (HTTP 401) when Referer/Origin headers missing. Browsers work because they auto-send these headers. Fixed by:
|
||||
- Adding `Referer` and `Origin` headers to all login requests
|
||||
- Headers set to qBittorrent base URL (e.g., `https://seedbox.example.com:443/qbittorrent`)
|
||||
- Applied to both `login()` and `testConnectionWithCredentials()` methods
|
||||
- Works with all qBittorrent versions and configurations
|
||||
|
||||
## Tech Stack
|
||||
|
||||
|
||||
Reference in New Issue
Block a user