Manual Instrumentation in NodeJS
Why Manual Instrumentation
Manual instrumentation allows developers to gain fine-grained control over the monitoring and observability of their applications by adding specific traces and metrics that automatic instrumentation might miss.
When to Use Manual Spans
- Detailed Business Logic Tracking: For tracing specific business processes and operations.
- Performance Bottlenecks: To identify and analyze performance issues in critical sections of your application.
- Error Handling and Debugging: For tracking and recording detailed error information and exceptions.
When to Use Custom Metrics
- Performance Monitoring: For tracking specific performance metrics like response times or processing durations.
- Resource Utilization: To monitor and manage resource usage, such as memory and CPU consumption.
- Business KPIs: For capturing key performance indicators relevant to your business logic.
Set Up Custom Spans
Install Dependencies
If you haven't already, install the necessary OpenTelemetry libraries:
npm install @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/resources @opentelemetry/semantic-conventions
Acquiring a Tracer
Acquire a tracer to create spans:
import { trace } from '@opentelemetry/api'
const tracer = trace.getTracer('your-service-name')
Adding Custom Spans
Example of adding a custom span in a function:
async function yourFunction() {
return tracer.startActiveSpan('your-span-name', async (span) => {
try {
// Start a new active span named 'your-span-name'
span.addEvent('Event description') // Add an event with a description to the span
span.setAttribute('attributeKey', 'attributeValue') // Set an attribute on the span
span.setStatus({ code: SpanStatusCode.OK }) // Set the status of the span to OK
} catch (error) {
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message }) // Set the status to ERROR if an exception occurs
span.recordException(error) // Record the exception in the span
throw error
} finally {
span.end() // End the span
}
})
}
Running the Application
Run your application normally, ensuring the tracing configuration is loaded first.
Verifying the Manual Spans
Check SigNoz for the manually created spans and verify the attributes and events are correctly logged.
For more detailed instructions with a sample app, refer to the complete article in the series: Manual Instrumentation for Traces - OpenTelemetry NodeJS
Set Up Custom Metrics
Setup Metric Collection
Create a telemetry.js
file and configure the MeterProvider
with an OTLPMetricExporter
:
import { metrics } from '@opentelemetry/api'
import {
MeterProvider,
PeriodicExportingMetricReader,
ConsoleMetricExporter,
} from '@opentelemetry/sdk-metrics'
import { Resource } from '@opentelemetry/resources'
import {
SEMRESATTRS_SERVICE_NAME,
SEMRESATTRS_SERVICE_VERSION,
} from '@opentelemetry/semantic-conventions'
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'
// Define resource with service name
const resource = Resource.default().merge(
new Resource({
[SEMRESATTRS_SERVICE_NAME]: 'your-service-name',
})
)
// Configure OTLP metrics exporter
const otlpMetricsExporter = new OTLPMetricExporter({
url: 'http://otel-collector:4318/v1/metrics', // ensure the port is correct
})
const metricReader = new PeriodicExportingMetricReader({
exporter: otlpMetricsExporter,
// Default is 60000ms (60 seconds). Set to 10 seconds for demonstrative purposes only.
exportIntervalMillis: 10000,
})
// Initialize MeterProvider
const myServiceMeterProvider = new MeterProvider({
resource: resource,
readers: [metricReader],
})
// Set this MeterProvider to be global to the app being instrumented.
metrics.setGlobalMeterProvider(myServiceMeterProvider)
- Here,
your-service-name
is the name you give to your service, which helps identify it in SigNoz. Replaceyour-service-name
with a unique name that describes the service's function. otel-collector
refers to the OpenTelemetry Collector endpoint where your application will send its metrics. Make sure this URL points to the correct location of your OpenTelemetry Collector instance.
Collect Metrics in Business Logic
Modify your business logic to measure and record metrics.
import { performance } from 'perf_hooks'
const meter = metrics.getMeter('your-service-name')
async function yourFunction(parameter) {
const startTime = performance.now()
const yourMetric = meter.createHistogram('your-metric-name', {
description: 'Description of your metric',
})
// Your business logic here
const duration = performance.now() - startTime
yourMetric.record(duration, { attributeKey: 'attributeValue' })
}
- Replace
your-service-name
with the name you give to your service. your-metric-name
is the name you give to the metric you are creating. It should be a unique and descriptive name that reflects what the metric is measuring.- The
Description of your metric
provides additional context about what the metric represents, helping others understand its purpose.
Running the Application
Run your application ensuring the telemetry configuration is loaded first.
Verifying and Visualizing Metrics
- Ensure your application is running and sending metrics.
- Use your observability platform's dashboard to visualize the metrics.
- Create a visualization to display the recorded metrics.
For more detailed instructions, refer to the complete article with a sample app in the series: Setting up Custom Metrics - OpenTelemetry NodeJS