Logging to Seq from the browser

As more functionality moves to the browser it can be useful to send log events to Seq directly from the browser. This can be accomplished using the seq-logging library.

Diagram showing log events going directly from the browser to Seq

This posts describes one way to send structured log events from the browser to Seq, and how it can be used to enable logging client-side errors and browser performance metrics.

You’ll then be able to collect events from your client side logs and search them in one central place:

Seq showing metric events, with one expanded

Adding seq-logging to a browser application

seq-logging is a Node.js library for sending structured log events to Seq. By default it will not work in the browser. It can be made to work in the browser by polyfilling its Node.js dependencies. Developers using webpack to bundle their  JavaScript application may polyfill Node.js dependencies using the node-polyfill-webpack-plugin, by adding the package and configuring webpack to use it.

  1. Add node-polyfill-webpack-plugin to your project's dependencies

> npm install node-polyfill-webpack-plugin

  1. Configure webpack to use node-polyfill-webpack-plugin. In webpack.config.js:
let NodePolyfillPlugin = require('node-polyfill-webpack-plugin');

module.exports = {
	// ...
	plugins: [
            new NodePolyfillPlugin({
                includeAliases: ['http','https','url','Buffer','process']
            }),
	]
    // ...
};

With this setup, client-side JavaScript can use the Node.js API and webpack will provide an implementation that works in the browser. seq-logging can now be added to the project.

> npm install seq-logging

Once  seq-logging is installed events can be sent to Seq.

let seq = require('seq-logging');

let logger = new seq.Logger({ 
    serverUrl: 'https://your-seq-server:5341' 
});

logger.emit({
    timestamp: new Date(),
    level: 'Information',
    messageTemplate: 'Hello for the {n}th time!',
    properties: {        
        n: 20
    }
});

logger.close();

Logging from a React application

A more complete example is to add client-side event logging to a React application. Start by creating a new React application with create-react-app.

> npx create-react-app log-from-browser

To be able to modify webpack's configuration in webpack.config.js 'eject' the application from create-react-app.

> npm run eject

Now add node-polyfill-webpack-plugin and seq-logging:

> npm install node-polyfill-webpack-plugin seq-logging

Next, configure webpack to polyfill the Node.js APIs. Locate /config/webpack.config.js, require node-polyfill-webpack-plugin and add new NodePolyfillPlugin() to the plugins array of the exported object.

const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
// ...
module.exports = {
	// ...
    plugins: [
    	new NodePolyfillPlugin({
        	includeAliases: ['http','https','url','Buffer','process']
      	}),
        // ...
    ],
    // ...
};
// ...

In /src/index.js create a logger and log something:

import seq from 'seq-logging';

const logger = new seq.Logger({ 
    serverUrl: 'https://your-seq-server:5341' 
});

logger.emit({
    timestamp: new Date(),
    level: 'Information',
    messageTemplate: 'Test logging from react'
});

Then start the app with npm start.

When the app starts it sends an event to Seq.

Logging errors

To send unhandled exceptions to Seq, register a handler for the window's error event:

window.addEventListener("error", (e) => {
  try {  
    logger.emit({
      timestamp: new Date(),
      level: 'Error',
      messageTemplate: 'JavaScript error: {message}',
      properties: {
          type: e.type,
          message: e.message,
      }
    });
  }
  catch {}
});

With this event handler configured all unhandled exceptions that occur in the browser will be recorded as errors in Seq.

Logging core web vitals

Core web vitals are an emerging set of browser user experience metrics. Some of the most important metrics are:

  • Largest Contentful Paint (LCP) - the time from when the page first starts to load until the main content is loaded.
  • First Input Delay (FID) - the time from a user action until the page responds.
  • Cumulative Layout Shift (CLS) - measures the amount of rapid repositioning of rendered elements.

The create-react-app (version 5.0.1) template comes setup to read core web vitals metrics. There is a placeholder in index.js.

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

The callback provided to reportWebVitals is called whenever a core web vitals metric is available. It can be used to send the metric values to Seq.

reportWebVitals(metric => {
  logger.emit({
    timestamp: new Date(),
    level: 'Debug',
    messageTemplate: 'Core web vitals metric {name}',
    properties: {
        ...metric        
    }
  });
});

Monitoring these metrics helps to maintain a good user experience for web applications. Seq can visualise each metric over time.

Or calculate statistics for each metric.

The core web vitals metrics come with recommended target values for "good" user experience. For example, it is recommended that first input delay (FID) be less than 100ms. Seq can easily create an alert that will generate a notification when the recommended value is exceeded.

Creating an alert for each core web vitals metric of interest provides visibility into the actual user experience of users. If a bug, or feature, introduces a user interface performance problem it can be detected immediately.

Final considerations

It may be preferable to send logs to Seq via your application server, instead of directly. This allows you to keep Seq off the public network and closed to public ingestion. Depending upon circumstances this may, or may not, be necessary.

Seq is designed for developers who need visibility into the execution of software systems. Extending this visibility into the browser can illuminate the last dark corner of many systems.

Liam McLennan

Read more posts by this author.