Skip to content

Logging Infrastructure

Overview

The API uses a structured logging pipeline:

API Container → stdout (JSON) → PromtailLokiGrafana

ServiceImagePortBindingPurpose
Lokigrafana/loki:3.4.23100127.0.0.1 (localhost only)Log storage & query engine
Promtailgrafana/promtail:3.4.29080Internal onlyScrapes Docker container logs
Grafanagrafana/grafana:11.5.230000.0.0.0 (all interfaces)Dashboard & alerting UI

Accessing Logs

Remote Access via Grafana

Grafana is bound to all interfaces and accessible remotely:

http://<server-ip>:3000

Default credentials: admin / admin

Important: Change the default password immediately when exposing Grafana to the network. Set GF_SECURITY_ADMIN_PASSWORD in docker-compose.yml or change it on first login.

Pre-built Dashboard

An API Overview dashboard is auto-provisioned with:

  • Request Rate by Endpoint
  • Error Rate Over Time
  • Request Latency (p50/p95/p99)
  • Active Users
  • Total Requests (1h)
  • Error Count (1h)
  • Top Endpoints
  • Recent Errors (detailed log view)

The dashboard auto-refreshes every 30 seconds and shows the last hour of data.

LogQL Queries

In Grafana, go to Explore → select Loki datasource:

# All API logs
{service="org-chart-api"}
# Errors and fatals only
{service="org-chart-api", level=~"error|fatal"}
# Logs for a specific endpoint
{service="org-chart-api"} | json | path="/api/orgcharts"
# Request rate over time
count_over_time({service="org-chart-api"} [1m])
# Filter by request ID
{service="org-chart-api"} | json | requestId="abc-123"
# Filter by user
{service="org-chart-api"} | json | userId="user-id-here"

Raw Docker Logs

For quick access without Grafana:

Terminal window
docker compose logs -f api # Follow API logs
docker compose logs -f --tail=100 api # Last 100 lines
docker compose logs -f loki # Loki health
docker compose logs -f promtail # Promtail scraping status

Security: Port Bindings

Internal services are bound to localhost only to prevent unauthorized network access:

ServicePortBindingRemote Access
API87890.0.0.0Yes (public API)
Grafana30000.0.0.0Yes — dashboard UI
Redis6379127.0.0.1No (localhost only)
Loki3100127.0.0.1No (localhost only)

Loki and Redis do not need external access. Promtail and Grafana communicate with them over the internal Docker network. The 127.0.0.1 binding keeps them off the network while still allowing local debugging via SSH.

Recommendations for Internet-Facing Servers

  1. Change the default Grafana password — set GF_SECURITY_ADMIN_PASSWORD in docker-compose.yml
  2. Firewall — restrict port 3000 to your IP or trusted networks
  3. Reverse proxy — put Grafana behind Nginx/Caddy with HTTPS

Alerting

Three alert rules are pre-configured in Grafana:

AlertConditionSeverity
High Error Rate>10 errors/minWarning
Fatal Error DetectedAny fatal-level logCritical
API Heartbeat MissingNo logs for 5 minutesCritical

Email Alerts

Set these environment variables in .env to enable email alerts on error/fatal logs:

RESEND_API_KEY=your_resend_api_key

Configuration

Environment Variables

VariableDefaultDescription
LOG_LEVELinfo (prod) / debug (dev)Minimum log level
LOKI_URLhttp://loki:3100Loki endpoint (internal)
ALERT_EMAILEmail for error/fatal alerts
RESEND_API_KEYResend API key for email delivery

Log Levels

debug (0) → info (1) → warn (2) → error (3) → fatal (4)

Data Retention

  • Retention period: 30 days (configured in config/loki.yml)
  • Storage: Local filesystem via Docker volume loki_data
  • Compaction: Runs every 10 minutes

Config Files

FilePurpose
config/loki.ymlLoki server and storage configuration
config/promtail.ymlLog scraping rules and label extraction
config/grafana-provisioning/Grafana datasources and alert rules
config/dashboards/api-overview.jsonPre-built Grafana dashboard