Skip to content

Add Sentry Logs for the backend and SSR frontend - #1336

Merged
daveearley merged 1 commit into
developfrom
feat/sentry-logging
Sep 5, 2026
Merged

Add Sentry Logs for the backend and SSR frontend#1336
daveearley merged 1 commit into
developfrom
feat/sentry-logging

Conversation

@daveearley

Copy link
Copy Markdown
Contributor

Ships application logs to Sentry Logs from both services, behind a single env contract.

The backend already had sentry/sentry-laravel 4.25.1, which includes the Logs feature as a Monolog handler β€” so every existing Log:: call ships with no call-site changes. The SSR side gains the equivalent via consoleLoggingIntegration.

Nothing is enabled by default. SENTRY_ENABLE_LOGS defaults to false and self-hosted installs have no Sentry DSN wired at all, so their behaviour is byte-identical to today.

Env contract

Same names and values on both sides, so a deployment sets them once:

Variable Backend SSR frontend
SENTRY_DSN / SENTRY_SSR_DSN βœ“ βœ“ (separate projects)
SENTRY_ENVIRONMENT βœ“ (falls back to APP_ENV) βœ“ (warns if unset)
SENTRY_RELEASE βœ“ (from github.sha) βœ“
SENTRY_ENABLE_LOGS βœ“ βœ“
SENTRY_LOG_LEVEL βœ“ βœ“
SENTRY_TRACES_SAMPLE_RATE βœ“ βœ“

SENTRY_LOG_LEVEL accepts Monolog level names on both sides (warning β†’ warn, critical β†’ fatal), so one value means the same thing in each service.

Bugs fixed along the way

SENTRY_ENABLE_LOGS=1 crashed the app at boot. Laravel's env() leaves "1" a string and Sentry's OptionsResolver requires a real bool, so ClientBuilder::create() threw InvalidOptionsException before the app could serve a request. Now coerced with filter_var.

An empty LOG_STACK silently killed all logging. explode(',', '') yields [""], and LogManager::get() swallows the resulting exception and falls back to the emergency logger β€” so logs would vanish from docker logs into a container-layer file with no error. Now sanitised with a fallback to single.

The SSR instrumentation never initialised from .env. instrument.mjs runs via node --import, which is evaluated before server.js imports dotenv/config β€” so SENTRY_SSR_DSN in .env was invisible and Sentry silently did nothing locally. Fixed by importing dotenv first.

Deprecated sendDefaultPii replaced with dataCollection. It's removed in v11, and a naive swap would have been worse than the status quo: dataCollection defaults to collecting cookies, headers and request bodies. server.js reads a JWT from req.cookies.token, so every category is now explicitly disabled.

Staging would have reported as production. SENTRY_ENVIRONMENT appeared nowhere in the repo, and yarn start hardcodes NODE_ENV=production via cross-env, so both DO apps would have landed in the same bucket. It's now required, with a loud boot warning when missing.

Also

  • SENTRY_RELEASE wired from github.sha on Vapor deploys.
  • .do/app.yaml deleted β€” a stale spec describing demo.hi.events with the backend on DigitalOcean and Postgres 12, none of which is current. Nothing referenced it; the README deploy buttons point at the separate HiEventsDev/hi.events-digitalocean repo, and the live DO apps are driven by ID through the API.

Verification

  • 17 env permutations exercised across both services: missing DSN, missing environment, log gating on/off, every SENTRY_LOG_LEVEL spelling including invalid input, release and traces set, plus the Docker shape (vars injected, no .env on disk).
  • Confirmed APP_ENV correctly drives the backend's Sentry environment, and that an explicit SENTRY_ENVIRONMENT overrides it.
  • Backend --testsuite=Unit: 1127 tests, no failures. pint passes. tsc --noEmit clean for the touched files.

Deploy notes

  • Backend config is cached at build time (php artisan optimize in vapor.yml), so these take effect on the next deploy, not on an env update β€” and there is no fast kill switch during an incident.
  • Vapor env vars are already set for staging and production; the DigitalOcean apps still need SENTRY_SSR_DSN and SENTRY_ENVIRONMENT at RUN_TIME scope.
  • @sentry/node pulls in OpenTelemetry (~15 transitive packages, including module-loader patching via import-in-the-middle) β€” worth a look at SSR cold-start before this goes to production.

Not included

No browser-side Sentry β€” this covers the SSR process only, so client-side React errors are still uncaptured. Adding the browser SDK means bundle size, source map upload and PII decisions, so it belongs in its own change. Source maps are likewise not uploaded, which means SSR render stack traces will be minified.

Ships Laravel `Log::` calls to Sentry Logs via the sentry_logs Monolog
channel, and console output from the SSR server via consoleLoggingIntegration.
Both services share one env contract: SENTRY_ENVIRONMENT, SENTRY_RELEASE,
SENTRY_ENABLE_LOGS and SENTRY_LOG_LEVEL mean the same thing on each side.

Backend:
- Add the sentry_logs channel and make the stack channel list env-driven
  via LOG_STACK, tolerating empty and whitespace-padded values so a
  misconfigured stack cannot silently fall back to the emergency logger.
- Coerce SENTRY_ENABLE_LOGS with filter_var. Sentry's OptionsResolver
  requires a real bool, so SENTRY_ENABLE_LOGS=1 previously threw
  InvalidOptionsException during boot.

Frontend:
- Load dotenv inside instrument.mjs. Because it runs via --import it was
  evaluated before server.js loaded dotenv, so SENTRY_SSR_DSN in .env was
  never visible and Sentry silently never initialised.
- Gate enableLogs on SENTRY_ENABLE_LOGS and filter by SENTRY_LOG_LEVEL,
  accepting Monolog level names so both services behave identically.
- Warn at boot when SENTRY_ENVIRONMENT is unset instead of silently
  reporting staging traffic as production.
- Replace deprecated sendDefaultPii with dataCollection, disabling every
  category. The new defaults collect cookies and headers, and the SSR
  server reads a JWT from req.cookies.token.

Also wires SENTRY_RELEASE from github.sha on Vapor deploys and removes
.do/app.yaml, a stale app spec describing infrastructure no longer in use.
@railway-app
railway-app Bot temporarily deployed to Hi.Events / Hi.Events-pr-1336 September 5, 2026 08:15 Destroyed
@railway-app

railway-app Bot commented Sep 5, 2026

Copy link
Copy Markdown

πŸš… Deployed to the Hi.Events-pr-1336 environment in Hi.Events

Service Status Web Updated
Hi.Events Frontend 😴 Sleeping (View Logs) Web Sep 5, 2026 at 8:25 am UTC
Hi.Events Queue Worker βœ… Success (View Logs) Sep 5, 2026 at 8:18 am UTC
Hi.Events Scheduler βœ… Success (View Logs) Sep 5, 2026 at 8:18 am UTC
Hi.Events API βœ… Success (View Logs) Web Sep 5, 2026 at 8:17 am UTC
1 service not affected by this PR
  • Maildev

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

βœ… E2E Β· smoke

βœ… Passed ❌ Failed ⚠️ Flaky ⏭️ Skipped ⏱️ Duration
25 0 0 0 1m 7s

View run

@daveearley
daveearley merged commit e9c2b08 into develop Sep 5, 2026
10 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 5, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant