Backend Logging
Structured logging for be/ using Pino (app) and Winston (workers).
Setup
App logger is in be/core/utils/logger.ts (Pino). Initialized once in be/core/index.ts.
Worker logger is in be/core/utils/winston-worker-logger.ts (Winston).
Rule: Never use console.log (even for quick user/debug checks). Use the logger helpers.
Pino covers all app logs; Winston is for worker-layer logs.
Log Types
| Type | Layer | Example |
|---|---|---|
INFRASTRUCTURE | Prisma, pools, startup | Server start |
REPO | Database access | StoreRepository.create |
SERVICE | Business logic | StoreService.createStore |
ROUTER | HTTP controllers | StoreRouter.createStore |
Log Levels
| Level | When |
|---|---|
INFO | Normal operations |
ERROR | Failures, exceptions |
WARN | Suspicious but non-fatal |
DEBUG | Verbose diagnostics (dev only) |
FATAL | Unrecoverable errors |
Service Logging Rule
- •Service layer logs should only emit
ERRORentries. AvoidINFOlogs in services.
Helpers
GeneralLogger
For cross-cutting/infrastructure logs:
typescript
import { GeneralLogger, LogType, LogLevel } from "@Ciri/utils/logger";
GeneralLogger(LogType.INFRASTRUCTURE, LogLevel.INFO, "Prisma client initialized");
UnitLogger
For scoped logs (router/service/repo):
typescript
import { UnitLogger, LogType, LogLevel } from "@Ciri/utils/logger";
UnitLogger(LogType.SERVICE, "StoreService.createStore", LogLevel.INFO, `Creating store for userId=${userId}`);
Worker Logger (Winston)
For BullMQ workers:
typescript
import { createWorkerLogger, logWorkerInfo, WorkerLogLevel } from "@Ciri/utils/winston-worker-logger";
const logger = createWorkerLogger("image-processing", job);
logWorkerInfo(logger, "Worker started");
logger.log(WorkerLogLevel.ERROR, "Image processing failed", { jobId: job.id });
Patterns
Router Layer
typescript
router.post("/createStore", async (req, res, next) => {
try {
// ... logic
} catch (error) {
UnitLogger(LogType.ROUTER, "StoreRouter.createStore", LogLevel.ERROR, error.message);
next(error);
}
});
Service Layer
typescript
async createStore(userId: string, name: string) {
const store = await this.storeRepo.create({ name });
return store;
}
Repository Layer
typescript
async create(data: Prisma.StoreCreateInput) {
UnitLogger(LogType.REPO, "StoreRepository.create", LogLevel.DEBUG, "Creating store");
return prisma.store.create({ data });
}
Unit Name Convention
- •Router:
StoreRouter.createStore - •Service:
StoreService.createStore - •Repository:
StoreRepository.create
Environment
- •
DEBUGlogs only show whenENVIRONMENT=dev - •In production, debug logs are skipped