rubis/apps/api/config/logger.ts
ordinarthur 68ed8f2ec6
All checks were successful
Build & Deploy Web / build-and-deploy (push) Successful in 29s
Build & Deploy API / build-and-deploy (push) Successful in 1m7s
feat(api): logs fichier en dev + traces du flow relance/mail
config/logger.ts: en dev, on duplique les logs vers
apps/api/storage/logs/app.log via un `multistream` pino (pretty stdout
+ JSON file en parallèle). Plus fiable que `transport.targets` qui
tourne dans un worker thread et fail silencieusement quand le path
n'est pas accessible.

Logs ciblés sur le pipeline relance pour debug rapide :
  - relance_scheduler : tâche créée + delaySec + queueJobId
  - send_relance_job  : pick-up / skip / envoi / OK / KO
  - mail_dispatcher   : driver actif (smtp/resend) + send OK / err

.gitignore : storage/uploads + storage/logs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 12:37:20 +02:00

101 lines
2.8 KiB
TypeScript

import { mkdirSync } from 'node:fs'
import env from '#start/env'
import app from '@adonisjs/core/services/app'
import {
defineConfig,
syncDestination,
targets,
multistream,
destination,
} from '@adonisjs/core/logger'
/**
* En dev on duplique les logs vers `apps/api/storage/logs/app.log` pour
* pouvoir grep / tail / partager facilement (notamment quand un job BullMQ
* tourne en arrière-plan et qu'on veut voir si l'envoi mail s'est bien fait
* sans devoir scroller le terminal).
*
* En prod on garde uniquement stdout (les logs sont collectés par K8s via
* `kubectl logs`).
*
* Implémentation : on utilise `multistream` (pino) qui écrit en parallèle
* - vers la sortie sync pretty (TTY) — la sortie habituelle dev
* - vers le fichier app.log en JSON (parseable, grep-able)
*
* Plus fiable que `transport.targets` qui tourne dans un worker thread et
* peut échouer silencieusement quand le path n'est pas accessible.
*/
const logFilePath = app.makePath('storage/logs/app.log')
if (!app.inProduction) {
mkdirSync(app.makePath('storage/logs'), { recursive: true })
}
const prettyStream = !app.inProduction ? await syncDestination() : null
const devDestination =
!app.inProduction && prettyStream
? multistream([
// Sortie console pretty (sync) — c'est la sortie habituelle dev.
{ stream: prettyStream },
// Fichier JSON ligne — destination pino classique avec append+mkdir.
{
stream: destination({
dest: logFilePath,
sync: true,
append: true,
mkdir: true,
}),
},
])
: undefined
const loggerConfig = defineConfig({
/**
* Default logger name used by ctx.logger and app logger calls.
*/
default: 'app',
loggers: {
app: {
/**
* Toggle this logger on/off.
*/
enabled: true,
/**
* Logger name shown in log records.
*/
name: env.get('APP_NAME'),
/**
* Minimum level to output (trace, debug, info, warn, error, fatal).
*/
level: env.get('LOG_LEVEL'),
/**
* Dev : multistream (pretty stdout + JSON file).
* Prod : pas de destination → AdonisJS bascule sur transport.
*/
destination: devDestination,
/**
* En prod : un seul transport vers stdout (collecté par K8s).
* En dev : pas de transport — le multistream ci-dessus s'occupe de
* tout, et mélanger les deux fait que pino ignore le destination.
*/
transport: app.inProduction
? { targets: [targets.file({ destination: 1 })] }
: undefined,
},
},
})
export default loggerConfig
/**
* Inferring types for the list of loggers you have configured
* in your application.
*/
declare module '@adonisjs/core/types' {
export interface LoggersList extends InferLoggers<typeof loggerConfig> {}
}