Analyzing Webserver Errors

In modern web development, monitoring and logging are critical aspects of maintaining robust and reliable applications. Telemetry allows developers to track various events and system metrics, which can be crucial for debugging and improving user experience. In this post, we’ll explore how to use the Telemetry API to catch and log all errors in an Express.js web server. Although this guide only covers Express, the ideas are applicable to all web servers, from Rails to Elixir, etc.

Setting Up Telemetry

Before we can log any data, we need to set up Telemetry. For this example, we'll use the Telemetry JavaScript SDK.

First, install the Telemetry SDK in your project:

npm install telemetry-sh

Then, initialize the Telemetry client in your application with your API key:

import telemetry from "telemetry-sh";

telemetry.init("YOUR_API_KEY");

Creating an Express Application

Next, let's set up a basic Express application. If you don't already have Express installed, you can add it to your project with the following command:

npm install express

Now, create a simple Express server:

const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`);
});

Middleware for Error Handling

To catch and log all errors, we need to create a middleware function that will handle errors. This middleware should be added after all other middleware and route handlers.

// Error handling middleware
app.use((err, req, res, next) => {
  // Log the error using Telemetry
  telemetry.log('express_errors', {
    message: err.message,
    stack: err.stack,
    path: req.path,
    method: req.method,
    timestamp: new Date().toISOString()
  });

  // Respond with a generic error message
  res.status(500).send('Something went wrong!');
});

Example Error Route

For demonstration purposes, let's create a route that will throw an error:

app.get('/error', (req, res) => {
  throw new Error('This is a test error');
});

Complete Example

Here’s the complete code for an Express server with error logging using Telemetry:

const express = require('express');
const telemetry = require('telemetry-sh');

telemetry.init("YOUR_API_KEY");

const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.get('/error', (req, res) => {
  throw new Error('This is a test error');
});

// Error handling middleware
app.use((err, req, res, next) => {
  // Log the error using Telemetry
  telemetry.log('express_errors', {
    message: err.message,
    stack: err.stack,
    path: req.path,
    method: req.method,
    timestamp: new Date().toISOString()
  });

  // Respond with a generic error message
  res.status(500).send('Something went wrong!');
});

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`);
});

Querying and Displaying Error Data

Now, let's query the logged errors and use the data in a simple dashboard. We'll query the error logs and display them in an HTML table.

First let's create the JSON endpoint to get the data from Telemetry:

app.get('/api/errors', async (req, res) => {
  const results = await telemetry.query(`
    SELECT
      message,
      stack,
      path,
      method,
      timestamp
    FROM
      express_errors
    ORDER BY
      timestamp DESC
    LIMIT 10
  `);

  res.json(results);
});

Lastly we create a simple HTML dashboard to display the error data:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Error Dashboard</title>
</head>
<body>
  <h1>Error Dashboard</h1>
  <table border="1">
    <thead>
      <tr>
        <th>Timestamp</th>
        <th>Message</th>
        <th>Path</th>
        <th>Method</th>
        <th>Stack</th>
      </tr>
    </thead>
    <tbody id="data-table">
      <!-- Data will be inserted here -->
    </tbody>
  </table>

  <script>
    (async () => {
      const response = await fetch('/api/errors');
      const results = await response.json();

      const tableBody = document.getElementById('data-table');
      results.forEach(row => {
        const tr = document.createElement('tr');
        tr.innerHTML = `
          <td>${row.timestamp}</td>
          <td>${row.message}</td>
          <td>${row.path}</td>
          <td>${row.method}</td>
          <td>${row.stack}</td>
        `;
        tableBody.appendChild(tr);
      });
    })();
  </script>
</body>
</html>

Conclusion

By following these steps, you can easily integrate Telemetry into your Express application to catch and log all errors. This setup will help you monitor and debug your application more effectively, ensuring a better experience for your users. The Telemetry API provides a powerful tool for tracking various events and metrics, and with the JavaScript SDK, integrating it into your projects is straightforward and efficient.

Last updated