Node.js Logging with Winston and Traces with OpenTelemetry

Ship data from your Node.js application to Logit.io

For developers working with Node.js, seamlessly sending logs and traces to Logit.io can unlock valuable insights for debugging, monitoring, and improving system reliability. This guide will help you configure your node.js application to send logs and traces to your Logit.io stack and analyse the data in OpenSearch Dashboards (for logs) or Jaeger (for traces).

The guide below will help you get started with sending logs and traces from your Node.js application to Logit.io.

If you only want to send APM data, you can skip to the APM section.

If you only want to send logs, continue to the next section below.

Logs

Get started quickly with Node.js logging using our configuration guide on how to easily ship Node.js logs to your hosted Logstash and OpenSearch.

Install Integration

Please click on the Install Integration button to configure your stack for this source.

Introduction

The example code used in this guide has been setup using Node.js v20.18.0 (64-bit). Node Package Manager (npm) can be used to install the required winston (3.17.0) and winston-logstash (1.2.1) packages.

These will allow you to send log data from your Node.js application, to your Logit.io stack.

Installing

First, ensure that you have downloaded and installed Node.js. You can get it from the official website, here (opens in a new tab). This includes various options to install including using an installer file (for Windows or Mac).

If you are just starting out with sending logs via Node.js there is a useful tutorial for creating an 'express' application to help get you up-and-running here (opens in a new tab).

We will be using this express application as a base for our example code.

Once you have created the app, inside your project directory, open a terminal of your choice and enter the following commands in turn. This will use Node Package Manager to install the app dependencies and the latest version of Winston and winston-logstash:

npm install
npm install winston
npm install winston-logstash

For additional information, the official Winston documentation can be found here (opens in a new tab).

Sending Logs

To setup Winston, add a file called logger.js in the root directory of the application and paste the following code into it:

 
const winston = require('winston');
const LogstashTransport = require("winston-logstash/lib/winston-logstash-latest");
 
const logger = winston.createLogger({
  transports: [
    new LogstashTransport({
      port: '@logstash.sslPort:strip_quotes',
      host: '@logstash.host',
      ssl_enable: true,
      max_connect_retries: -1,
    })
  ]
});
 
module.exports = logger;

Update app.js to reference the logger.js file and add the logger to the application:

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var morganMiddleware = require('morgan');
 
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
 
const logger = require('./logger');
 
var app = express();
 
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
 
app.use(morganMiddleware('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
 
app.use('/', indexRouter);
app.use('/users', usersRouter);
 
// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});
 
// error handler
app.use(function(err, req, res, next) {
  logger.error(err.message, { metadata: err });
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};
 
  // render the error page
  res.status(err.status || 500);
  res.render('error');
});
 
module.exports = app;

You can then send logs using a Winston log method. For example, in the index.js file inside the routes folder, you can add the following code to send a log message when navigating to the home page.

Replace the index.js content with the following code:

var express = require('express');
var router = express.Router();
const logger = require('../logger');
 
/* GET home page. */
router.get('/', function(req, res, next) {
  logger.info('Hello, this is a log message from the index page!');
  res.render('index', { title: 'Express' });
});
 
module.exports = router;

Run the application using the following command in the terminal:

npm start

If you then navigate to the home page of the application (http://localhost:3000/ (opens in a new tab)), it will send the log message to your Logit.io stack.

You can send different levels of log records by using different Winston log methods. Other log record levels and their corresponding winston methods include:

logger.log("This is a standard log message");
logger.error("This is an error log message");
logger.warn("This is a warning log message");

Launch Logs to View Your Data

Launch Logs

How to diagnose no data in Stack

If you don't see data appearing in your stack after following this integration, take a look at the troubleshooting guide for steps to diagnose and resolve the problem or contact our support team and we'll be happy to assist.

APM

Install Integration

Please click on the Install Integration button to configure your stack for this source.

Install

Create a new folder for the project called opentelemetry_nodejs_example and then open the command prompt or terminal window and navigate to the folder. Paste in the following command:

npm init -y

This will create a package.json file with default settings.

This guide uses the Express framework to simplify handling HTTP requests. Next we need to paste the following command into the command prompt or terminal window:

npm install express

You will now have a node_modules folder in addition to the package.json and a package-lock.json file.

We now need to install the necessary OpenTelemetry packages using npm (node package manager), the packages that we will be using are as follows:

  • opentelemetry-api: Core API for OpenTelemetry
  • opentelemetry-sdk: SDK implementation
  • opentelemetry-exporter-trace-otlp-grpc: Exporter to send data to the OpenTelemetry Collector or other OTLP-compatible backends using grpc
  • opentelemetry-exporter-trace-otlp-http: Exporter to send data to the OpenTelemetry Collector or other OTLP-compatible backends using https
  • opentelemetry-instrumentation-node: Automatically instrument your node applications for tracing with OpenTelemetry

We install them with the following command.

npm install @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-http @opentelemetry/exporter-trace-otlp-grpc

Create three new files and name them app.js, tracing.js and config.js.

Open the tracing.js file with your choice of text editor, copy and paste the following code into the file and then save.

tracing.js
const config = require('./config');
 
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { resourceFromAttributes } = require('@opentelemetry/resources');
const { ATTR_SERVICE_NAME } = require('@opentelemetry/semantic-conventions');
const { OTLPTraceExporter } = require(`@opentelemetry/exporter-trace-otlp-${config.protocol}`);
let sdk = new NodeSDK();
let channelCredentials = null;
let traceExporter = new OTLPTraceExporter();
 
// Define the service name
const serviceName = 'LogitNodeJSTestApp';
 
// Encode the username and password for Basic Authentication
const auth = Buffer.from(`${config.username}:${config.password}`).toString('base64');
 
if (config.protocol === "grpc") {    
  const OTLP_ENDPOINT = `grpc://${config.endpoint}:${config.port}`;
  const grpc = require('@grpc/grpc-js');
  const { credentials } = grpc;
  const metadata = new grpc.Metadata();
  metadata.set('authorization', `Basic ${auth}`);
  
  // Create gRPC credentials with Basic Auth
  channelCredentials = credentials.combineChannelCredentials(
    credentials.createSsl(), // Use SSL credentials if your endpoint requires it
    credentials.createFromMetadataGenerator((_params, callback) => {
    callback(null, metadata);
    })
  );
  
  // Configure the OTLP trace exporter with gRPC and Basic Auth
  traceExporter = new OTLPTraceExporter({
    url: OTLP_ENDPOINT,
    credentials: channelCredentials,
  });
  
  // Create a new Node SDK instance with automatic instrumentation
  sdk = new NodeSDK({
    traceExporter,
    instrumentations: [getNodeAutoInstrumentations()],
    resource: resourceFromAttributes({
        [ATTR_SERVICE_NAME]: serviceName,
      }),
  });
} else {    
  const OTLP_ENDPOINT = `https://${config.endpoint}:${config.port}/v1/traces`;
  
  // Create HTTPS credentials with Basic Auth
  traceExporter = new OTLPTraceExporter({
  url: OTLP_ENDPOINT,
  headers: {
    'Authorization': `Basic ${auth}`
    }
  });
  
  // Create a new Node SDK instance with automatic instrumentation
  sdk = new NodeSDK({
    traceExporter,
    instrumentations: [getNodeAutoInstrumentations()],
    resource: resourceFromAttributes({
        [ATTR_SERVICE_NAME]: serviceName,
      }),
  });
}
 
// Initialize the SDK and start the tracing
sdk.start();

Next open the app.js file with your text editor, copy and paste the following code into the file and then save.

app.js
// Import and initialize OpenTelemetry
require('./tracing');
 
const express = require('express');
const app = express();
 
app.get('/', (req, res) => {
  res.send('Hello, World!');
});
 
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

Configuring the App

Open the config.js file using your text editor, copy and paste the following into the file and then save. Use the tab to choose between sending via HTTPS or gRPC.

// config.js
module.exports = {
  endpoint: "@opentelemetry.endpointAddress",
  port: "@opentelemetry.httpsPort",
  protocol: "http",
  username: '@opentelemetry.username',
  password: '@opentelemetry.password',
};

Run the NodeJs App

Run the NodeJS app with the following command in Terminal or the Command Prompt window.

node app.js

You will see feedback from the app so that you know that is running, the message should say "Server is running on http://localhost:3000 (opens in a new tab)".

If you open your browser and enter http://localhost:3000 (opens in a new tab) you will see that action of browsing to the page served by the NodeJS app will send traces to your stack.

Launch Logit.io to view your traces

Launch APM

How to diagnose no data in stack

If you don't see data appearing in your stack after following this integration, take a look at the troubleshooting guide for steps to diagnose and resolve the problem or contact our support team and we'll be happy to assist.