Skip to content

ADR-0007 — EvoLogger facade kept instead of migrating to pino

Status: Accepted Date: 2026-04-16 Author(s): Platform engineering

Context

After adopting nestjs-pino as the Nest framework logger (see ADR-0001), ~40 call sites across all five NestJS apps still use EvoLogger — a winston-backed logging facade from @bebkovan/server-core. The natural question: should those 40 call sites be migrated to pino?

Both loggers now produce trace-correlated output:

  • Pino records carry trace_id, span_id, trace_flags via @opentelemetry/instrumentation-pino (configured in libs/shared/src/basic/pre/pre-otel.main.ts:78-82). Records are bridged into the OTel logs SDK and exported via OTLP to the Collector → Loki.
  • EvoLogger/winston records carry the same three fields via WinstonInstrumentation (enabled by default in getNodeAutoInstrumentations). Records go to docker stdout and reach Loki via the filelog/docker Collector receiver.

Both paths produce trace-correlated, queryable logs in Loki. The difference is the ingest route, not the observability value.

Decision

Keep EvoLogger as-is. Do not migrate the ~40 call sites to pino. New code should prefer the Nest-injected pino logger (constructor(private logger: Logger) from nestjs-pino), but existing EvoLogger call sites are not worth touching.

Alternatives considered

  1. Migrate all ~40 EvoLogger call sites to pino. Rejected: touches 40+ files across every module. Every call site already produces trace-tagged, Loki-queryable output. The migration adds risk (each EvoLogger.log()this.logger.log() requires injecting a Nest Logger into the constructor, potentially changing class initialization order) for zero observability gain.

  2. Remove the @bebkovan/server-core dependency entirely. Rejected: EvoLogger is not the only export from @bebkovan/server-core. Other utilities from the package are still in use. Removing the dependency requires auditing all imports, not just the logger.

  3. Write a pino-backed EvoLogger shim (same API, pino transport). Rejected: adds complexity for marginal benefit. The EvoLogger API and pino's Logger API are different enough that a shim would be a maintenance surface. The two-logger setup already works.

Consequences

  • Two logger APIs coexist. New engineers should read ADR-0001 and the observability doc to understand which logger to use where.
  • EvoLogger records in Loki are tagged source=docker_filelog and lack service.name resource attributes. Query them with {source="docker_filelog"} |= "EvoLogger".
  • Pino records in Loki arrive via OTLP with full OTel resource attributes (service.name, service.version). Query them with {service_name="ebit-api"}.
  • If @bebkovan/server-core is ever removed from the dependency tree for unrelated reasons, the 40 EvoLogger call sites must be migrated at that time — but as a consequence of the dependency removal, not as a standalone effort.

References

  • libs/shared/src/basic/pre/pre-otel.main.ts:78-82 — PinoInstrumentation with custom logKeys
  • libs/shared/src/logger/pino-logger.module.tsNestLoggerModule.forRoot()
  • libs/shared/src/basic/base.main.tsapp.useLogger(app.get(Logger)) framework logger swap
  • ADR-0001 — Pino + Winston coexistence decision
  • docs/observability.md — two-logger explanation and Loki query recipes