DevOps & SRE

Get more insights with the new version of the Node.js library

nodejs.jpg

We’re thrilled to announce the release of a new update to the Cloud Logging Library for Node.js with the key new features of improved error handling and writing structured logging to standard output which becomes handy if you run applications in serverless environments like Google Functions!

The latest v9.9.0 of Cloud Logging Library for Node.js makes it even easier for Node.js developers to send and read logs from Google Cloud providing real-time insight into what is happening in your application through comprehensive tools like Log Explorer. If you are a Node.js developer working with Google Cloud, now is a great time to try out Cloud Logging.

The latest features of the Node.js library are also integrated and available in other packages which are based on Cloud Logging Library for Node.js:

If you are unfamiliar with the Cloud Logging Library for Node.js, start by running following command to add the library to your project:

  npm install @google-cloud/logging

Once the library is installed, you can use it in your project. Below, I demonstrate how to initialize the logging library, create a client assigned configured with a project ID,  and log a single entry 'Your log message':

  // Imports the Google Cloud client library 
 const { Logging } = require('@google-cloud/logging');
 // Creates a client with predefined project Id and a path to
 // credentials JSON file to be used for auth with Cloud Logging
 const logging = new Logging(
   {
     projectId: 'your-project-id',
     keyFilename: '/path/to/key.json',
   }
 );
 // Create a log with desired log name
 const log = logging.log('your-log-name');
 // Create a simple log entry without any metadata
 const entry = log.entry({}, 'Your log message');
 // Log your record!!!
 log.info(entry);

Here's the log message generated by this code in Log Explorer:

1 nodejs library.jpg

Two critical features of the latest Cloud Logging Library for Node.js release are writing structured log entries to standard output and error handling with a default callback. Let's dig in deeper. 

Writing structured log entries to standard output

The LogSync class helps users write context-rich structured logs to stdout or any other Writable interface. This class extracts additional log properties like trace context from HTTP headers, and can be used to toggle between writing to the Cloud Logging endpoint or to stdout during local development.

In addition, writing structured logging to stdout can be integrated with a Logging agent. Once a log is written to stdout, a Logging agent then picks up those logs and delivers those to Cloud Logging out-of-process. Logging agents can add more properties to each entry before streaming it to the Logging API.

We recommend serverless applications (i.e. applications running in Cloud Functions and Cloud Run) to use the LogSync class as async logs delivery may be dropped due to lack of CPU or other environmental factors  preventing the logs from being sent immediately to the Logging API. Cloud Functions and Cloud Run applications by their nature are ephemeral and can have a short lifespan which will cause logging data drops when an instance is shut down before the logs have been sent to Cloud Logging servers. 

Today, Google Cloud managed services automatically install Logging agents for all Google serverless environments in the resources that they provision - this means that you can use LogSync in your application to seamlessly deliver logs to Cloud Logging through standard output.

Below is a sample how to use LogSync class:

  const { Logging } = require('@google-cloud/logging');
 const logging = new Logging(
   {
     projectId: 'your-project-id',
     keyFilename: '/path/to/key.json',
   }
 );
// Create a LogSync transport, defaulting to `process.stdout`
const log = logging.logSync('Your-log-name');
const entry = log.entry({}, 'Your log message');
log.write(entry);

If you use @google-cloud/logging-winston  or @google-cloud/logging-bunyan library, you can set the redirectToStdout parameter in LoggingWinston or LoggingBunyan constructor options respectively. Below is a sample code how to redirect structured logging output to stdout for LoggingWinston class:

  // Imports the Google Cloud client library for Winston
const {LoggingWinston} = require('@google-cloud/logging-winston');

// Creates a client that writes logs to stdout
const loggingWinston = new LoggingWinston({
  projectId: 'your-project-id',
  keyFilename: '/path/to/key.json',
  redirectToStdout: true,
});

Error Handling with a default callback

The Log class provides users the ability to write and delete logs asynchronously. However, there are cases when log entries cannot be written or deleted and an error is thrown - if the error is not handled properly, it can crash the application. 

One possible way to handle the error is to await the log write/delete calls and wrap it with try/catch. However, waiting for every write or delete call may introduce delays which could be avoided by simply adding a callback as shown below:
  // Asynchronously write the log entry and handle response or 
   // any errors in provided callback
    log.write(entry, err => {
      if (err) {
        // The log entry was not written.
        console.log(err.message);
      } else {
        console.log('No error in write callback!');
      }
    });

Adding a callback to each write or delete call is duplicate code and remembering to include it for each call may be toilsome, especially if  the code handling the error is always the same. To eliminate this burden, we introduced the ability to provide a default callback for the Log class which can be set through the LogOptions passed to the Log constructor as in example below:

  const {Logging} = require('@google-cloud/logging');
  const logging = new Logging();
  
  // Create options with default callback to be called on 
  // every write/delete response or error
  const options = {
    defaultWriteDeleteCallback: function (err) {
      if (err) {
        console.log('Error is: ' + err);
      } else {
        console.log('No error, all is good!');
      }
    },
  };

  const log = logging.log('my-log', options);

If you use @google-cloud/logging-winston  or @google-cloud/logging-bunyan library, you can set the callback through defaultCallback parameter in LoggingWinston or LoggingBunyan constructor options respectively. Here is an example of  how to set a default callback for LoggingWinston class:

  // Imports the Google Cloud client library for Winston
const {LoggingWinston} = require('@google-cloud/logging-winston');

// Creates a client
const loggingWinston = new LoggingWinston({
  projectId: 'your-project-id',
  keyFilename: '/path/to/key.json',
  defaultCallback: err => {
    if (err) {
      console.log('Error occurred: ' + err);
    }
  },
});

Next Steps

  • Now, when you integrate the Cloud Logging Library for Node.js in your project, you can start using the latest features. 
  • To try the latest Node.js library in Google Cloud you can follow this quickstart walkthrough guide:
guide me button.jpg