From 421cd97fe96d3e010dd7c39fc3b40eb699875537 Mon Sep 17 00:00:00 2001 From: Michael Mainguy Date: Tue, 13 Jan 2026 17:21:29 -0600 Subject: [PATCH] Add console log forwarding to New Relic and enable application logging - Add console shim to forward log/error/warn/info to New Relic - Enable application_logging with forwarding in newrelic.cjs - Import newrelic in server.js for recordLogEvent API - Update CI workflow with New Relic config Co-Authored-By: Claude Opus 4.5 --- .github/workflows/build.yml | 1 + newrelic.cjs | 18 +++++++++++++--- server.js | 41 +++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0259d12..7946d80 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -57,6 +57,7 @@ jobs: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + NEW_RELIC_LICENSE_KEY: ${{ secrets.NEW_RELIC_LICENSE_KEY }} run: | # Create .env.production with secrets (only accessible by immersive user) echo "# Auto-generated by CI/CD - Do not edit manually" > /opt/immersive/.env.production diff --git a/newrelic.cjs b/newrelic.cjs index 91c7b37..72709b7 100644 --- a/newrelic.cjs +++ b/newrelic.cjs @@ -1,5 +1,7 @@ 'use strict' - +// Load .env.local first (has the secrets), then .env as fallback +require('dotenv').config({ path: '.env.local' }); +require('dotenv').config(); /** * New Relic Node.js APM Configuration * @@ -10,14 +12,24 @@ */ exports.config = { - app_name: ['dasfad'], - license_key: process.env.NEW_RELIC_KEY, + app_name: ['dasfad-backend'], + license_key: process.env.NEW_RELIC_LICENSE_KEY, distributed_tracing: { enabled: true }, logging: { level: 'info' }, + application_logging: { + enabled: true, + forwarding: { + enabled: true, + max_samples_stored: 10000 + }, + local_decorating: { + enabled: true + } + }, allow_all_headers: true, attributes: { exclude: [ diff --git a/server.js b/server.js index c793b82..ba1ba43 100644 --- a/server.js +++ b/server.js @@ -2,6 +2,7 @@ import express from "express"; import ViteExpress from "vite-express"; import cors from "cors"; import dotenv from "dotenv"; +import newrelic from "newrelic"; import apiRoutes from "./server/api/index.js"; import { pouchApp, PouchDB } from "./server/services/databaseService.js"; import { dbAuthMiddleware } from "./server/middleware/dbAuth.js"; @@ -10,6 +11,46 @@ import { dbAuthMiddleware } from "./server/middleware/dbAuth.js"; dotenv.config({ path: '.env.local' }); dotenv.config(); +// Console shim to forward logs to New Relic while preserving local output +const originalConsole = { + log: console.log.bind(console), + error: console.error.bind(console), + warn: console.warn.bind(console), + info: console.info.bind(console) +}; + +function forwardToNewRelic(level, args) { + const message = args.map(arg => + typeof arg === 'object' ? JSON.stringify(arg) : String(arg) + ).join(' '); + + newrelic.recordLogEvent({ + message, + level, + timestamp: Date.now() + }); +} + +console.log = (...args) => { + forwardToNewRelic('info', args); + originalConsole.log(...args); +}; + +console.error = (...args) => { + forwardToNewRelic('error', args); + originalConsole.error(...args); +}; + +console.warn = (...args) => { + forwardToNewRelic('warn', args); + originalConsole.warn(...args); +}; + +console.info = (...args) => { + forwardToNewRelic('info', args); + originalConsole.info(...args); +}; + const app = express(); // CORS configuration for split deployment