Configuration
LokiLoggerModule.register accepts a rich set of options for production workloads. This page documents each option and its default as implemented in LokiLoggerOptions.
Basic options
import { LokiLoggerModule } from "@planetmoondrop/centralized-logger";
LokiLoggerModule.register({
serviceName: "auth-service",
lokiHost: "http://loki:3100",
environment: process.env.NODE_ENV ?? "development",
logLevel: "info",
});serviceName(required, string)- Unique name for this microservice.
- Used as the
applabel in Loki and Prometheus metrics.
lokiHost(required, string)- Base URL of your Loki instance, e.g.
http://loki:3100See Deployment.
- Base URL of your Loki instance, e.g.
environment(optional, string)- Deployment environment label (
envin Loki,envin Prometheus). - Default:
process.env.NODE_ENV ?? 'development'.
- Deployment environment label (
extraLabels(optional,Record<string,string>)- Static labels added to every log line, e.g.
{ region: 'us-east-1', team: 'platform' }.
- Static labels added to every log line, e.g.
Trace headers
These control how trace IDs are propagated between services.
traceHeader(string, default:'x-loki-trace-id')parentSpanHeader(string, default:'x-parent-span-id')
All internal components – middleware, LokiHttpService, and the frontend client – assume these defaults. If you change them:
- Update:
app.enableCors({ exposedHeaders: [...] })inmain.ts.- Any proxies or API gateways that forward headers.
Log levels & console output
-
logLevel('debug' | 'info' | 'warn' | 'error', default:'info') Minimum level forwarded to Loki and console. -
consoleOutput(boolean, default:false)- When
true, logs are also printed to stdout. - When
false, logs go only to Loki via the internal transport.
- When
-
jsonConsole(boolean, default:false)- When
true, console logs are structured JSON. - When
false, console logs are colorized + human readable.
- When
Production tip:
Use consoleOutput: true only if your platform relies on stdout logs (e.g. Kubernetes log collection). For purely Loki-based setups, it is safe (and cheaper) to keep console output off.
Loki buffering & retry
These options, control how logs are buffered and retried before being sent to Loki.
-
lokiBatchInterval(number, default:5000) Interval in milliseconds between push attempts. -
lokiRetries(number, default:3) Retry attempts per batch on failure (network errors, 5xx responses, timeouts). -
lokiBufferSize(number, default:5000) Maximum number of log entries kept in memory. -
bufferLogsWhenUnreachable(boolean, default:false)false(default): after all retries, failed batches are dropped.true: failed batches are re-queued (up tolokiBufferSize) and retried later.
Production recommendation:
- For memory-constrained workloads: keep
bufferLogsWhenUnreachableatfalseso sustained Loki outages cannot cause memory pressure. - For critical audit trails where losing logs is unacceptable: set
bufferLogsWhenUnreachable: trueand increaselokiBufferSize, monitoring memory via Prometheus.
Request / response bodies
These options add HTTP body payloads to logs.
logRequestBody(boolean, default:false)logResponseBody(boolean, default:false, truncated to ~2KB)
Both are useful for debugging but may log sensitive data.
Never enable
logRequestBodyorlogResponseBodyin production unless you have explicit approval and strong data-governance controls.
When either flag is enabled in production, LokiLoggerService emits a warning at startup.
Field redaction
Use redactFields to automatically scrub sensitive keys from all log payloads before they reach Loki or console.
LokiLoggerModule.register({
// ...
redactFields: ["password", "token", "authorization", "secret", "apiKey"],
});redactFields(string[], default:[])- Recursive: any key with a matching name at any depth is replaced with
'[REDACTED]'.
- Recursive: any key with a matching name at any depth is replaced with
You can hide specific key-value pairs, so even nested objects and arrays are safe.(Recommended for production)
Trace viewer
These options control the built-in trace viewer API and SPA mounted by LokiLoggerModule.mountViewer(app).
-
enableTraceViewer(boolean, default:false)- When
true,mountViewerregisters:GET {traceViewerPath}→ HTML SPA.GET {traceViewerPath}/api/:traceId→ structured JSON trace.
- When
-
traceViewerPath(string, default:'/_trace')- Base path for the viewer and its API.
-
traceViewerServices(string, default:serviceName)- Comma‑separated list of service names to query in Loki.
- Example:
'auth-service,business-service,gateway'.
If the viewer is enabled but traceViewerServices is left at the default, the module logs a warning that only the current service’s logs will be included in cross-service traces.
Prometheus metrics
These options power the /metrics endpoint and Grafana dashboards.
-
enableMetrics(boolean, default:false)- When
true,apply(app)mounts a/metricsendpoint on your Express instance.
- When
-
metricsPath(string, default:'/metrics')- Path used by the mounted endpoint.
Metrics include:
http_request_duration_seconds(Histogram) – latency per route/method/status.http_requests_total(Counter) – total requests by route/method/status.http_requests_in_flight(Gauge) – concurrent requests.- Default Node.js process metrics (heap, GC, CPU, event loop, etc.).
See Prometheus metrics for wiring scraping and Grafana dashboards.
OpenTelemetry / Tempo tracing
Tracing has two parts:
- SDK bootstrap with
initObservability(beforeNestFactory.create). - Loki options that decide whether to prefer OTEL trace/span IDs.
Relevant settings:
-
enableTracing(boolean, default:false)- When
true, the middleware and logger attempt to read the active OTEL span context viagetActiveOtelContextand reuse its traceId/spanId.
- When
-
otlpEndpoint(string, default:'http://localhost:4318')- Base OTLP HTTP endpoint for
initObservability.
- Base OTLP HTTP endpoint for
You still need to call initObservability({ serviceName, otlpEndpoint }) – see OpenTelemetry & Tempo.
Multi‑tenancy / API keys
apiKey(optional, string)- Sent as the
X-Scope-OrgIDheader on every Loki push. - Use this for multi‑tenant Loki deployments or per‑team scoping.
- Sent as the
LokiLoggerModule.register({
serviceName: "payments-api",
lokiHost: "https://loki.mycompany.com",
apiKey: "team-payments-prod",
});You can generate a random ID using:
node -e "console.log(require('crypto').randomUUID())"Async configuration with ConfigService
For real deployments, prefer registerAsync to pull values from .env / a config service:
import { ConfigModule, ConfigService } from "@nestjs/config";
import { LokiLoggerModule } from "@planetmoondrop/centralized-logger";
@Module({
imports: [
ConfigModule.forRoot(),
LokiLoggerModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
serviceName: config.get<string>("SERVICE_NAME") ?? "my-service",
lokiHost: config.get<string>("LOKI_HOST") ?? "http://loki:3100",
environment: config.get<string>("NODE_ENV") ?? "development",
logLevel: config.get<"debug" | "info" | "warn" | "error">("LOG_LEVEL", "info"),
enableMetrics: config.get<boolean>("ENABLE_METRICS", true),
enableTracing: config.get<boolean>("ENABLE_TRACING", false),
apiKey: config.get<string>("LOKI_API_KEY"),
}),
}),
],
})
export class AppModule {}This pattern mirrors the configuration style used throughout the NestJS ecosystem and keeps your deployment environments fully configurable without code changes.
Need help or want to support the project? Visit Support us.