Logging vs reporting (twee systemen)

In de backend bestaan twee los van elkaar staande systemen die makkelijk door elkaar worden gehaald. Dit document legt uit wat het verschil is en wanneer je welk systeem kiest. Voor concrete feiten (env-vars, endpoints, API) zie de reference-docs: Platform-logging en Reporting en eventservice.

Het mentale model

  Platform-logging Reporting
Doel Vluchtige runtime-diagnostiek (debuggen, troubleshooten) Duurzaam verslag van wat een proces heeft gedaan
Service loggerService (pino) + logStore reportingService (alias logService) → eventService
Waar het landt stdout + in-memory/Redis ringbuffer MongoDB events-collectie
Levensduur Kort (TTL, standaard 7 dagen; ringbuffer rolt) Permanent (tot expliciet verwijderd)
Zichtbaar via GET /logs + Tapster-beheer “Logging” Tijdlijn, en kan notificaties triggeren
Eenheid Losse regels per log-call Eén Event per proces-run (gebundeld)

Kort gezegd: logging is voor de ontwikkelaar/on-call, reporting is voor de business/audit. Een logregel beantwoordt “wat gebeurde er net in de code”; een Event beantwoordt “wat heeft deze run verwerkt, en kun je dat later terugvinden”.

Platform-logging

loggerService is een dunne contextuele wrapper rond pino. Er zijn vier bronnen (app, http, bull, error), elk met een eigen pino-instance. Elke log-call gaat naar stdout (en optioneel naar dagbestanden) én naar een unified logStore (in-memory of Redis), die de admin-UI en GET /logs voeden.

Gebruik dit voor: business-acties, state-changes, fouten, job start/finish, HTTP-requests. Het is bewust vluchtig: de ringbuffer heeft een maximum en een TTL. Reken er niet op voor langetermijn-audit.

Zie ook ADR 0001 — log-level voor HTTP-fouten.

Reporting

reportingService (in de codebase geïmporteerd als logService via een alias) verzamelt tekstregels in een in-memory context, en zet ze bij flush() om in precies één Event. Het is event-only: de oude e-mail- en console-transports bestaan niet meer, en de transportName-parameter van flush() wordt genegeerd.

eventService is de laag eronder: het maakt het Event aan, plaatst het op de tijdlijn en kan op basis van het EventType notificaties versturen. Een Event kan gekoppeld zijn aan een bron-document via sourceDoc { id, model } (de model moet in de onModelRegistry staan, anders kan de tijdlijn-populate en notificatie-dispatch het niet resolven).

Gebruik dit voor: import/export, batch-jobs, migraties, data-repair en andere processen met een duidelijk begin en einde waarvan je een navigeerbaar verslag wilt bewaren.

Een concreet voorbeeld: process-response

De deelnamemonitor-campagne (processResponse) is een goed voorbeeld van waarom de twee systemen naast elkaar bestaan:

  • Tijdens de verwerking schrijft de code per locatie een regel (“Locatie verwerkt X”, “Tag niet gevonden … overgeslagen”). Dat zou je vluchtig kunnen loggen.
  • Aan het einde wil je weten: welke campagne, door wie gestart, hoeveel verwerkt / overgeslagen / niet-verwerkt, en dat verslag terug kunnen vinden bij de campagne.

Daarom gebruikt processResponse de reportingService: het bundelt de regels en flusht ze als één Event met sourceDoc { model: 'ParticipationMonitorCampaign' }, de triggerende gebruiker en een gestructureerde samenvatting. Dat is reporting, niet platform-logging.

Vuistregel

  • Moet het na een week nog terugvindbaar zijn, of hoort het op een tijdlijn / bij een document? → reporting (reportingService / eventService).
  • Is het diagnostiek die je morgen tijdens debuggen wilt kunnen filteren? → logging (loggerService / req.logger).
  • Geen console.log in business-code; gebruik altijd een van bovenstaande.