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.
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:
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.
- Add
node-polyfill-webpack-plugin
to your project's dependencies
> npm install node-polyfill-webpack-plugin
- Configure webpack to use
node-polyfill-webpack-plugin
. Inwebpack.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.