Collecting Nodejs winston logs

If you are using winston as your logging library in your Nodejs application, you can export these logs to SigNoz very easily using various transports provided by winston.

📝 Note

The default logging level can be configured.

To send all the logs to SigNoz please change the default log level to DEBUG.

const logger = winston.createLogger({
  level: 'debug',
  // ... other configurations
});

For SigNoz Cloud

For sending logs to SigNoz cloud, while running the above example set the below environment variables

  • The value of OTEL_EXPORTER_OTLP_ENDPOINT environment variable will be https://ingest.{region}.signoz.cloud:443/v1/logs where depending on the choice of your region for SigNoz cloud, the otlp endpoint will vary according to this table.

    RegionEndpoint
    USingest.us.signoz.cloud:443
    INingest.in.signoz.cloud:443
    EUingest.eu.signoz.cloud:443
  • The value of SIGNOZ_ACCESS_TOKEN environment variable will be <SIGNOZ_INGESTION_KEY> where <SIGNOZ_INGESTION_KEY> is your ingestion key

How to collect logs from Node.js Winston without the requiring Otel collectors

  • First we will install a few dependencies using npm

    npm install @opentelemetry/api-logs @opentelemetry/sdk-logs @opentelemetry/exporter-logs-otlp-http @opentelemetry/winston-transport @opentelemetry/resources winston dotenv
    
  • logger.js

    const logsAPI = require('@opentelemetry/api-logs')
    const { LoggerProvider, SimpleLogRecordProcessor } = require('@opentelemetry/sdk-logs')
    const { OTLPLogExporter } = require('@opentelemetry/exporter-logs-otlp-http')
    const { OpenTelemetryTransportV3 } = require('@opentelemetry/winston-transport')
    const { Resource } = require('@opentelemetry/resources')
    const winston = require('winston')
    require('dotenv').config()
    
    // Initialize the Logger provider
    const loggerProvider = new LoggerProvider({
      resource: new Resource({
        'service.name': 'winston-logger',
        'service.version': '1.0.0',
        'deployment.environment': process.env.NODE_ENV || 'development',
      }),
    })
    
    // Configure OTLP exporter for SigNoz
    const otlpExporter = new OTLPLogExporter({
      url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
      headers: {
        'signoz-access-token': process.env.SIGNOZ_ACCESS_TOKEN,
      },
    })
    
    // Add processor with the OTLP exporter
    loggerProvider.addLogRecordProcessor(new SimpleLogRecordProcessor(otlpExporter))
    
    // Set the global logger provider
    logsAPI.logs.setGlobalLoggerProvider(loggerProvider)
    
    // Create Winston logger with Console and OpenTelemetry transports
    const logger = winston.createLogger({
      level: 'debug',
      format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.errors({ stack: true }),
        winston.format.metadata(),
        winston.format.json()
      ),
      defaultMeta: {
        service: 'winston-logger',
        environment: process.env.NODE_ENV || 'development',
      },
      transports: [
        new OpenTelemetryTransportV3({
          loggerProvider,
          logAttributes: {
            'service.name': 'winston-logger',
            'deployment.environment': process.env.NODE_ENV || 'development',
          },
        }),
      ],
    })
    
    module.exports = logger
    
    • example index.js
    const express = require('express')
    const logger = require('./logger')
    const PORT = process.env.PORT || '5555'
    const app = express()
    
    app.use(express.json())
    
    app.get('/', (req, res) => {
      logger.log('debug', 'Hello, World!') //debug level as first param
      logger.debug("The is the home '/' route.")
      // using debug method directly
      res.json({ method: req.method, message: 'Hello World', ...req.body })
    })
    
    app.get('/404', (req, res) => {
      logger.error('404 error') //error method
      logger.debug('The is the 404 route.')
      res.sendStatus(404)
    })
    
    app.get('/user', (req, res) => {
      try {
        throw new Error('Invalid user')
      } catch (error) {
        logger.error('Auth Error: invalid user')
        logger.debug('The is the user route.')
        res.status(500).send('Error!')
      }
    })
    
    app.listen(parseInt(PORT, 10), () => {
      console.log(`Listening on http://localhost:${PORT}`)
    })
    
  • We will modify the OTLPLogExporter to

    OTLPLogExporter(url="0.0.0.0:4317")
    

    Here we are using 0.0.0.0 as our host since we are running this application in the same machine where SigNoz is running, for other configurations please check the troubleshooting guide.

  • Now you can run your application by running node index.js

  • If there are no errors your logs will be visible on SigNoz UI.

Collecting Nodejs logs when application is deployed on Docker or Kubernetes

When your application is deployed in Docker or a Kubernetes cluster, the logs from the console are automatically collected and stored in the node. The SigNoz collector will automatically collect the logs and they will be visible on the SigNoz UI.

Console Transport Configuration

You can easily add a console transport to your Winston logger with the following code:

logger.add(new winston.transports.Console(options))

The Console transport supports several configuration options:

  • level: Specifies the level of messages this transport should log (default: level set on parent logger).
  • silent: A boolean flag to suppress output (default is false).
  • eol: Defines the end-of-line characters to use (default is os.EOL).
  • stderrLevels: An array of log levels to be sent to stderr instead of stdout. For example: ['error', 'debug', 'info'] (default is an empty array).
  • consoleWarnLevels: An array of log levels to use console.warn() or stderr (in Node.js) instead of stdout. For example: ['warn', 'debug'] (default is an empty array).

Example configuration:

logger.add(
  new winston.transports.Console({
    level: 'info',
    format: winston.format.simple(),
    silent: false,
    stderrLevels: ['error'],
  })
)

By using these configuration options, you can fine-tune how your logs are output and collected when deployed in containerized environments like Docker or Kubernetes.

Collecting Nodejs logs when application is deployed on a Host

When you run your application directly on the host, you will be required to add a intermediary medium ex:- a file, where you can export your logs and the otel-collector can read them and push to signoz.

You can add a file transport very easily as stated here.

logger.add(new winston.transports.File({
  filename: path.join(process.cwd(), 'logs', 'application.log'),
  level: 'debug',
  handleExceptions: true,
  maxsize: 5242880, // 5MB
  maxFiles: 5,
  tailable: true,
}));

Once you run your application and the logs are added to a file, you can configure otel collector to read from that file.

For configuring it you can follow the guide here.

Once you configure the otel collector the logs will be visible on the UI.

Was this page helpful?