Zephyr Mays
Zephyr Mays

Reputation: 487

Node.js logging to pm2 in standalone build

Goal: display console.log() and/or process.stdout.write() statements from server side routes to pm2 monit dashboard when running my Node.js app as a production standalone.

For example, .next/standalone/.next/server/app/api/weather/route.js has two logging statements:

        // Log the weather data to the console
        console.log("\n*********************\nWeather fetch() API Response:", {
            timestamp: timeStamp,
            Epoch: data.current_conditions.time,
            temp: data.current_conditions.air_temperature,
            wind: data.current_conditions.wind_avg
        });
        process.stdout.write(`Weather fetch() API Response: ${JSON.stringify({
            timestamp: timeStamp,
            Epoch: data.current_conditions.time,
            temp: data.current_conditions.air_temperature,
            wind: data.current_conditions.wind_avg
        })}\n`);

When envoking npm run dev these statements are correctly logged to the terminal.

Problem: After building as a standalone with "build:standalone": "NODE_ENV=production next build && cp .env.production .next/standalone/.env.production && cp -R .next/static .next/standalone/.next/static" and this next.config.mjs, no statements are logged.

import dotenv from "dotenv";
import path from "path";

/**
 * @type {import('next').NextConfig}
 */
const nextConfig = {
  basePath: "/tempestvue",
  trailingSlash: true, // Recommended for apps with a basePath
  swcMinify: false, // Disable minification
  reactStrictMode: false, // Disable React strict mode
  env: {
    BASE_PATH: process.env.BASE_PATH || "/tempestvue",
    REACT_APP_BASE_PATH: process.env.REACT_APP_BASE_PATH || "/tempestvue",
  },

  webpack: (config) => {
    config.optimization.minimize = false; // Ensure no minification
    config.externals = [...config.externals, { canvas: "canvas" }]; // Required for Chart.js
    return config;
  },
};

// Determine the environment file
const envFile =
  process.env.NODE_ENV === "production" ? ".env.production" : ".env.local";
console.log(`Using environment file: ${envFile}`);

// Load .env.production or .env.local
dotenv.config({ path: path.resolve(process.cwd(), envFile) });

export default {
  ...nextConfig,
  output: "standalone",
  env: {
    ...Object.keys(process.env)
      .filter((key) => key.startsWith("NEXT_PUBLIC_")) // Only public variables are included
      .reduce((env, key) => {
        env[key] = process.env[key];
        return env;
      }, {}),
  },
};

Environment:

  1. When envoking the app with pm2 start ecosystem.config.js, the browser renders the app and all dynamically generated data from api routes at http://localhost:3000/tempestvue/.
  2. All route.ts contains export const runtime = 'nodejs';.
  3. I am using this ecosystem.config.js:
module.exports = {
  apps: [
    {
      name: "TempestVue", // Name of application in PM2
      script: ".next/standalone/server.js", // Path to the standalone server file
      instances: 1, // Number of instances to run (1 for now, you can use cluster mode later)
      exec_mode: "fork", // Mode: fork or cluster
      env: {
        NODE_ENV: "production", // Set environment to production
        BASE_PATH: "/tempestvue", // Add your basePath for runtime awareness
        NEXT_RUNTIME_ENV: "development", // Enables verbose logging in production
      },
      log_date_format: "YYYY-MM-DD HH:mm:ss", // Human-readable log timestamps
      error_file: "/var/log/pm2/tempestvue-error.log", // Error log location
      out_file: "/var/log/pm2/tempestvue-out.log", // Output log location
      merge_logs: true, // Combine logs into a single file per process
      max_restarts: 3, // Automatically restart the app if it crashes
      restart_delay: 5000, // Delay between restarts
    },
  ],
};

Envoking the app with pm2 start ecosystem.config.js and I see this in the logs:

tempestvue % pm2 logs TempestVue
[TAILING] Tailing last 15 lines for [TempestVue] process (change the value with --lines option)
32|TempestVue  | 2025-01-26 13:11:57:    ▲ Next.js 15.1.6
32|TempestVue  | 2025-01-26 13:11:57:    - Local:        http://localhost:3000
32|TempestVue  | 2025-01-26 13:11:57:    - Network:      http://0.0.0.0:3000
32|TempestVue  | 2025-01-26 13:11:57:
32|TempestVue  | 2025-01-26 13:11:57:  ✓ Starting...
32|TempestVue  | 2025-01-26 13:11:57:  ✓ Ready in 36ms

Yet, nothing from console.log() and/or process.stdout.write() statements present in server-side routes.

Is it that a different route handler (perhaps an Edge route or some other fallback) is actually serving the data, and thus the console.log() statements are never really being invoked?

Note: pm2-logrotate is enabled for production.

Upvotes: 0

Views: 38

Answers (0)

Related Questions