Trovella Wiki

Local Debugging

pino-pretty output, Sentry in development, inspecting logs, and troubleshooting observability locally.

This page covers how the observability stack behaves during local development and how to use it for debugging.

Pino in Development

When NODE_ENV is not "production", Pino uses pino-pretty for colorized, human-readable output instead of JSON:

// packages/logger/src/logger.ts
base.transport = {
  target: "pino-pretty",
  options: { colorize: true, translateTime: "HH:MM:ss.l" },
};

Output looks like this in the terminal:

14:30:15.123 INFO (http): tRPC request completed
    requestId: "a1b2c3d4-..."
    method: "POST"
    path: "/api/trpc/widget.create"
    durationMs: 42

This is the same information that would be JSON in production, but formatted for human reading. The service name appears in parentheses after the log level.

Changing Log Level

The default development log level is debug, showing all log output. To filter, set LOG_LEVEL in apps/web/.env:

# Show only warnings and errors
LOG_LEVEL=warn

# Show everything including debug
LOG_LEVEL=debug

# Default (when unset): debug in dev, info in production

Changes take effect on the next dev server restart (pnpm dev).

Sentry in Development

Sentry is conditionally active based on whether DSN environment variables are set:

  • Server/Edge: SENTRY_DSN in .env
  • Client: NEXT_PUBLIC_SENTRY_DSN in .env

Without DSN (Default)

When the DSN variables are not set (the default for local development), all Sentry SDK calls are no-ops. Sentry.captureException() does nothing. onRequestError does nothing. Session replay does not record. There is no performance overhead.

With DSN (Optional)

If you set the DSN variables locally, Sentry operates at full fidelity:

  • 100% trace sampling -- every request generates a performance trace (production uses 10%)
  • Session replay active -- 10% of sessions recorded, 100% on error
  • Source maps inline -- development builds include inline source maps, so stack traces are readable without uploading .map files

This is useful when debugging a Sentry-specific issue (testing replay behavior, verifying error grouping, etc.) but not needed for day-to-day development.

Inspecting Logs

Terminal Output

All Pino logs appear in the terminal where pnpm dev is running. Because the dev server uses Turbopack with hot module replacement, you see logs in real time as requests are processed.

To find a specific log entry, use your terminal's search function or pipe the dev server output through grep:

pnpm dev 2>&1 | grep "widget.create"

Filtering by Logger Name

Each logger factory produces output tagged with a service name:

FactoryService NameWhen You See It
getLogger("health")healthHealth check endpoint
getLogger("seed")seedDatabase seeding
createRequestLogger(req)httptRPC and standalone route handlers
createJobLogger("process-invoice")jobsBackground job execution

In pino-pretty output, the service name appears in parentheses: INFO (http): .... This helps distinguish between different sources when multiple operations are happening concurrently.

Request Correlation

Every request logger includes a requestId (random UUID). When a single request triggers multiple log entries, they all share the same requestId, making it straightforward to trace a request through the logs:

14:30:15.100 INFO (http): Creating widget
    requestId: "a1b2c3d4-..."
14:30:15.142 INFO (http): Widget created
    requestId: "a1b2c3d4-..."
14:30:15.143 INFO (http): tRPC request completed
    requestId: "a1b2c3d4-..."
    durationMs: 43

Health Check Debugging

Test the health endpoint locally to verify all Docker services are running:

curl -s http://localhost:3000/api/health | jq

Expected output when all services are up:

{
  "status": "healthy",
  "checks": {
    "database": { "ok": true, "latencyMs": 3 },
    "redis": { "ok": true, "latencyMs": 1 },
    "typesense": { "ok": true, "latencyMs": 5 }
  },
  "timestamp": "2026-04-08T14:30:00.000Z"
}

If a check shows ok: false, the corresponding Docker container is likely not running. Start it with:

pnpm docker:up

Then retry the health check. See Health Checks for the full troubleshooting table.

Common Local Issues

SymptomCauseFix
No log output at allconsole.log used instead of @repo/loggerESLint should catch this. Use the appropriate logger factory.
Logs appear as raw JSON in devNODE_ENV set to "production" locallyRemove or change NODE_ENV in .env to "development" or unset it
pino-pretty not foundMissing dev dependencyRun pnpm install from the repo root
Sentry not capturing errors locallyDSN not setSet SENTRY_DSN and NEXT_PUBLIC_SENTRY_DSN in apps/web/.env (optional for local dev)
Debug logs not appearing in productionExpected behaviorProduction defaults to info level. Set LOG_LEVEL=debug on the VM to temporarily enable debug output.
Duplicate error entriesLogging and re-throwing at multiple layersOnly log an error at the layer that handles it. Utilities should throw, not log.

On this page