Elastic APM with TypeScript: A Comprehensive Guide

In modern software development, monitoring and tracing the performance of applications is crucial. Elastic APM (Application Performance Monitoring) is a powerful tool that helps developers understand how their applications are performing, identify bottlenecks, and debug issues effectively. When combined with TypeScript, a typed superset of JavaScript, it provides a robust and type - safe environment for building and monitoring applications. This blog will delve into the fundamental concepts of Elastic APM with TypeScript, show you how to use it, cover common practices, and share some best practices.

Table of Contents

  1. Fundamental Concepts of Elastic APM and TypeScript
  2. Setting Up Elastic APM with TypeScript
  3. Usage Methods
  4. Common Practices
  5. Best Practices
  6. Conclusion
  7. References

1. Fundamental Concepts of Elastic APM and TypeScript

Elastic APM

Elastic APM is a part of the Elastic Stack (Elasticsearch, Logstash, Kibana). It allows you to monitor the performance of your applications in real - time. Elastic APM works by instrumenting your application code to capture transactions and spans.

  • Transactions: A transaction represents a logical unit of work in your application, such as an HTTP request or a background job. It has a start and an end time and can contain multiple spans.
  • Spans: Spans are sub - units of a transaction. They represent individual operations within a transaction, like a database query or an external API call.

TypeScript

TypeScript is a statically typed language that builds on JavaScript. It adds optional static types to JavaScript, which helps catch errors early in the development process. TypeScript code is transpiled to plain JavaScript, which can run in any JavaScript environment.

2. Setting Up Elastic APM with TypeScript

Prerequisites

  • Node.js and npm installed
  • An Elasticsearch and Kibana instance running (you can use Elastic Cloud for easy setup)

Step 1: Create a new TypeScript project

mkdir elastic - apm - typescript - example
cd elastic - apm - typescript - example
npm init -y
npm install typescript --save - dev
npx tsc --init

Step 2: Install Elastic APM Node.js agent

npm install @elastic/apm - node

Step 3: Configure Elastic APM

Create a index.ts file in the project root directory:

import apm from '@elastic/apm - node';

// Initialize the APM agent
const apmInstance = apm.start({
    serviceName: 'my - typescript - service',
    serverUrl: 'http://localhost:8200', // Replace with your APM Server URL
    environment: 'development'
});

// Now you can start using the APM agent in your application

3. Usage Methods

Capturing Transactions

import apm from '@elastic/apm - node';

const apmInstance = apm.start({
    serviceName: 'my - typescript - service',
    serverUrl: 'http://localhost:8200',
    environment: 'development'
});

// Start a new transaction
const transaction = apmInstance.startTransaction('my - transaction');

// Simulate some work
setTimeout(() => {
    // End the transaction
    transaction?.end();
}, 2000);

Capturing Spans

import apm from '@elastic/apm - node';

const apmInstance = apm.start({
    serviceName: 'my - typescript - service',
    serverUrl: 'http://localhost:8200',
    environment: 'development'
});

const transaction = apmInstance.startTransaction('my - transaction');
const span = transaction?.startSpan('my - span');

// Simulate some work within the span
setTimeout(() => {
    span?.end();
    transaction?.end();
}, 1000);

Error Handling

import apm from '@elastic/apm - node';

const apmInstance = apm.start({
    serviceName: 'my - typescript - service',
    serverUrl: 'http://localhost:8200',
    environment: 'development'
});

try {
    throw new Error('Something went wrong');
} catch (error) {
    apmInstance.captureError(error);
}

4. Common Practices

Instrumenting HTTP Requests

If you are building a web application, you can instrument HTTP requests easily. For example, with Express.js:

import express from 'express';
import apm from '@elastic/apm - node';

const apmInstance = apm.start({
    serviceName: 'my - typescript - service',
    serverUrl: 'http://localhost:8200',
    environment: 'development'
});

const app = express();

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

const port = 3000;
app.listen(port, () => {
    console.log(`Server running on port ${port}`);
});

The Elastic APM agent will automatically capture HTTP transactions and spans for incoming requests.

Instrumenting Database Queries

If you are using a database like MySQL or PostgreSQL, you can instrument database queries. For example, with mysql2 package:

import mysql from 'mysql2/promise';
import apm from '@elastic/apm - node';

const apmInstance = apm.start({
    serviceName: 'my - typescript - service',
    serverUrl: 'http://localhost:8200',
    environment: 'development'
});

async function queryDatabase() {
    const connection = await mysql.createConnection({
        host: 'localhost',
        user: 'root',
        password: 'password',
        database: 'test'
    });

    const [rows] = await connection.execute('SELECT * FROM users');
    await connection.end();
    return rows;
}

queryDatabase().then((rows) => {
    console.log(rows);
});

The Elastic APM agent will capture database query spans.

5. Best Practices

Use Custom Metrics

You can use custom metrics to track application - specific data. For example, you can track the number of successful transactions or the average response time of a particular API endpoint.

import apm from '@elastic/apm - node';

const apmInstance = apm.start({
    serviceName: 'my - typescript - service',
    serverUrl: 'http://localhost:8200',
    environment: 'development'
});

let successfulTransactions = 0;

const transaction = apmInstance.startTransaction('my - transaction');
try {
    // Simulate some work
    successfulTransactions++;
    apmInstance.setCustomContext({
        successfulTransactions
    });
} catch (error) {
    apmInstance.captureError(error);
} finally {
    transaction?.end();
}

Centralized Configuration

Keep your Elastic APM configuration in a centralized location, such as a configuration file. This makes it easier to manage and update the configuration across different environments.

// config.ts
export const apmConfig = {
    serviceName: 'my - typescript - service',
    serverUrl: 'http://localhost:8200',
    environment: process.env.NODE_ENV || 'development'
};

// index.ts
import apm from '@elastic/apm - node';
import { apmConfig } from './config';

const apmInstance = apm.start(apmConfig);

6. Conclusion

Elastic APM combined with TypeScript provides a powerful way to monitor and trace the performance of your applications. By understanding the fundamental concepts, setting up the agent correctly, using the various usage methods, following common practices, and applying best practices, you can gain valuable insights into your application’s performance and quickly identify and fix issues. With the ability to capture transactions, spans, and errors, and the support for custom metrics, Elastic APM with TypeScript is a great addition to any modern software development stack.

7. References