Ship Quote has a fully integrated observability pipeline that captures structured logs at the application layer and makes them searchable in a Grafana dashboard within seconds of each request. The pipeline runs four components in sequence: Winston emits JSON logs from the Express API, Morgan intercepts every HTTP request and feeds it into Winston, Promtail scrapes those logs from the Docker daemon and forwards them to Loki, and Grafana provides the query and visualization interface on top of Loki.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/plantasur-dev/ship-quote/llms.txt
Use this file to discover all available pages before exploring further.
Pipeline Overview
Winston Logger
The core logger is configured inapi/src/lib/logger/logger.js using the winston package:
stdout. The Docker json-file driver wraps each line in its own JSON envelope, which Promtail later unwraps.
Log Levels
The active level is controlled by theLOG_LEVEL environment variable and falls back to info when not set.
| Level | When to use |
|---|---|
error | Unhandled exceptions, 5xx responses |
warn | 4xx client errors, degraded states |
info | Normal HTTP requests, startup events |
debug | Internal computation, provider calls, cache hits |
Setting
LOG_LEVEL=debug causes Winston to emit verbose output including internal rate-engine calculations, MongoDB query details, and per-provider API call traces. This produces a high volume of log data and should not be used in production as it may impact performance and rapidly fill your Loki storage.Log Format
A typical structured log entry looks like this:event field is set to "http_requests" for all HTTP traffic, making it a reliable label to filter on in Grafana’s LogQL.
Morgan HTTP Logger
Morgan is the HTTP request logging middleware for Express. Rather than writing its own log format, it is wired directly into the Winston transport inapi/src/lib/logger/morgan.js:
- Log-level routing: The severity is derived automatically from the HTTP status code via
getLogLevelFromStatus.2xx/3xx→info,4xx→warn,5xx→error. This means failed requests surface immediately in Grafana when filtering onlevel=warnorlevel=error. logHttpRequesthelper: Forinfo-level entries, the helper callslogger.info('http_requests', { ...params, event: 'http_requests' }). Forwarnanderrorentries, it callslogger[method]({ ...params })directly without a message string, keeping the log object flat.- Null return: Morgan’s formatter returns
nullinstead of a string, preventing a duplicate plain-text line from appearing alongside the JSON output. - Test mode: When
NODE_ENV=test, the middleware falls back to Morgan’s built-indevformat so test output stays human-readable in CI logs. res.locals.logData: Controllers can attach extra context (such as matched agency or zone) tores.locals.logData; Morgan spreads it into the log entry automatically.
Promtail Configuration
Promtail runs as a Docker service alongside the API and is responsible for collecting container logs and forwarding them to Loki. Its configuration is mounted frominfra/monitoring/promtail/config.yml:
How Promtail Works
Docker service discovery (docker_sd_configs): Promtail connects to the Docker socket at /var/run/docker.sock and automatically discovers all running containers every 5 seconds. No manual log-path configuration is needed — new containers are picked up dynamically.
Relabeling: The __meta_docker_container_name metadata label (which Docker sets to /ship-quote-app-dev, /ship-quote-loki, etc.) is captured with a regex that strips the leading / and stored as the container label on every log stream. This lets you filter logs by container name directly in Grafana.
Pipeline stages: The json stage parses each log line as JSON and extracts the fields that Winston emits (service, method, status, level, event, path, responseTime, ip). The labels stage then promotes those extracted values into Loki stream labels, enabling efficient indexed filtering on common query dimensions.
Positions file: Promtail records its read offset in /tmp/positions.yaml. On container restart it resumes from the last position, ensuring no log lines are lost or duplicated.
Loki Configuration
Loki stores the log streams forwarded by Promtail. Its configuration is mounted frominfra/monitoring/loki/config.yml:
Storage Layout
| Path | Content |
|---|---|
/loki/index | BoltDB index files (one per 24-hour period) |
/loki/cache | BoltDB shipper read cache |
/loki/chunks | Raw compressed log chunks on the local filesystem |
/loki/compactor | Compaction working directory |
loki_data named Docker volume, so log data persists across Loki container restarts. The period: 24h index rotation means a new index shard is created each day, keeping individual shard sizes manageable.
auth_enabled: false disables Loki’s multi-tenant authentication. This is appropriate for a single-environment development or self-hosted setup. For a shared or internet-facing deployment, enable authentication and configure a reverse proxy in front of Loki.Grafana Setup
Grafana is exposed at http://localhost:3001. The default credentials areadmin / admin (set via the GF_SECURITY_ADMIN_USER and GF_SECURITY_ADMIN_PASSWORD environment variables in docker-compose.yml). Dashboard and data-source configurations are persisted in the grafana_data named volume.
Adding the Loki Data Source
Open the Data Sources settings
In Grafana, click the hamburger menu (☰) in the top-left corner, then navigate to Connections → Data sources.
Set the connection URL
In the URL field enter:Use the Docker service name
loki (not localhost) because Grafana and Loki run in the same Docker Compose network and resolve each other by service name.Save and test
Scroll to the bottom of the page and click Save & test. Grafana will verify the connection; you should see a green “Data source connected and labels found” confirmation.
Useful LogQL Queries
Once the Loki data source is connected, the following queries cover the most common monitoring scenarios. All API log lines:Environment Variable Reference
| Variable | Default | Description |
|---|---|---|
LOG_LEVEL | info | Winston log level (error, warn, info, debug). Set on the app service in docker-compose.yml. |
NODE_ENV | production | When set to test, Morgan switches to the dev plain-text formatter instead of the JSON transport. |