Elastic Apm
Instrument applications with Elastic APM and the ELK Stack for traces, logs, and metrics.
You are an expert in Elastic APM and the ELK Stack (Elasticsearch, Logstash, Kibana). You help developers instrument applications with Elastic APM agents, correlate traces with logs, build Kibana visualizations, and write Elasticsearch queries for deep observability.
## Key Points
- **Capturing request bodies in production** - Setting `captureBody: 'all'` leaks sensitive data; use `'errors'` or `'off'` in production.
- **Missing log correlation** - Without injecting trace IDs into logs, you cannot jump from a trace to its log lines in Kibana.
- **Single-node Elasticsearch in production** - Always run a cluster with replicas; a single node loses data on failure.
- **Not filtering health checks** - Synthetic health checks pollute APM transaction data and skew latency metrics.
- You already use Elasticsearch and Kibana for logging and want APM in the same stack.
- You need service maps and dependency visualization for microservice architectures.
- You want trace-log correlation without maintaining separate systems.
- You need self-hosted observability with full control over data retention.
- You are running the Elastic Stack on Kubernetes with ECK (Elastic Cloud on Kubernetes).
## Quick Example
```bash
npm install elastic-apm-node
```
```typescript
// WRONG - you lose all trace data
apm.start({
transactionSampleRate: 0, // No traces collected at all
});
// Use a reasonable rate like 0.1 (10%) for high-traffic services
```skilldb get observability-services-skills/Elastic ApmFull skill: 255 linesElastic APM Integration
You are an expert in Elastic APM and the ELK Stack (Elasticsearch, Logstash, Kibana). You help developers instrument applications with Elastic APM agents, correlate traces with logs, build Kibana visualizations, and write Elasticsearch queries for deep observability.
Core Philosophy
Unified Observability in Elastic
Elastic APM stores traces, metrics, and logs in Elasticsearch. A single data store means you can correlate a slow transaction trace with the exact log lines and host metrics without switching tools.
Agent Auto-Instrumentation
Elastic APM agents automatically instrument popular frameworks, databases, and HTTP clients. Add custom spans only for business-specific operations.
Kibana as the Analysis Layer
Kibana provides APM-specific views (service maps, trace waterfall, error grouping) plus full Elasticsearch query power through Discover and Lens.
Setup
Install the Node.js APM agent:
npm install elastic-apm-node
Initialize before any other require:
// apm.ts - import FIRST
import apm from 'elastic-apm-node';
apm.start({
serviceName: process.env.ELASTIC_APM_SERVICE_NAME || 'my-service',
serverUrl: process.env.ELASTIC_APM_SERVER_URL || 'http://localhost:8200',
secretToken: process.env.ELASTIC_APM_SECRET_TOKEN,
environment: process.env.NODE_ENV || 'development',
captureBody: 'errors',
transactionSampleRate: 1.0,
logLevel: 'info',
});
export default apm;
Docker Compose for the Elastic Stack:
version: '3.8'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.13.0
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- ES_JAVA_OPTS=-Xms1g -Xmx1g
ports:
- "9200:9200"
kibana:
image: docker.elastic.co/kibana/kibana:8.13.0
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
ports:
- "5601:5601"
apm-server:
image: docker.elastic.co/apm/apm-server:8.13.0
environment:
- output.elasticsearch.hosts=["http://elasticsearch:9200"]
- apm-server.host=0.0.0.0:8200
ports:
- "8200:8200"
Key Patterns
Do: Add custom spans for business operations
import apm from './apm';
async function processPayment(orderId: string, amount: number) {
const span = apm.startSpan('payment.process', 'external', 'stripe');
if (span) {
span.addLabels({ 'order.id': orderId, 'payment.amount': amount });
}
try {
const result = await stripe.charges.create({ amount, currency: 'usd' });
return result;
} catch (error) {
apm.captureError(error as Error);
throw error;
} finally {
span?.end();
}
}
Not: Setting sample rate to 0 in production
// WRONG - you lose all trace data
apm.start({
transactionSampleRate: 0, // No traces collected at all
});
// Use a reasonable rate like 0.1 (10%) for high-traffic services
Do: Correlate logs with trace IDs
import apm from './apm';
import pino from 'pino';
const logger = pino({
mixin() {
const traceIds = apm.currentTraceIds;
return {
'trace.id': traceIds['trace.id'],
'transaction.id': traceIds['transaction.id'],
'span.id': traceIds['span.id'],
};
},
});
// Logs automatically include trace context for correlation in Kibana
logger.info('Payment processed successfully');
Common Patterns
Elasticsearch Query for Error Analysis
POST /apm-*-error-*/_search
{
"size": 0,
"query": {
"bool": {
"filter": [
{ "term": { "service.name": "checkout-api" } },
{ "range": { "@timestamp": { "gte": "now-1h" } } }
]
}
},
"aggs": {
"error_groups": {
"terms": {
"field": "error.grouping_key",
"size": 10,
"order": { "_count": "desc" }
},
"aggs": {
"sample": {
"top_hits": {
"size": 1,
"_source": ["error.exception.message", "error.exception.type"]
}
}
}
}
}
}
Custom Transaction Filtering
// Filter health checks from APM data
apm.addFilter((payload) => {
if (payload.context?.request?.url?.pathname === '/health') {
return false; // Drop this transaction
}
return payload;
});
Kibana Saved Search via API
curl -X POST "http://localhost:5601/api/saved_objects/search" \
-H "kbn-xsrf: true" \
-H "Content-Type: application/json" \
-d '{
"attributes": {
"title": "Slow Transactions",
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"query\":{\"bool\":{\"filter\":[{\"range\":{\"transaction.duration.us\":{\"gte\":1000000}}}]}},\"index\":\"apm-*\"}"
}
}
}'
Alerting with Elasticsearch Watcher
{
"trigger": {
"schedule": { "interval": "1m" }
},
"input": {
"search": {
"request": {
"indices": ["apm-*-error-*"],
"body": {
"query": {
"bool": {
"filter": [
{ "term": { "service.name": "api-gateway" } },
{ "range": { "@timestamp": { "gte": "now-5m" } } }
]
}
}
}
}
}
},
"condition": {
"compare": { "ctx.payload.hits.total.value": { "gt": 50 } }
},
"actions": {
"notify_slack": {
"webhook": {
"scheme": "https",
"host": "hooks.slack.com",
"port": 443,
"method": "POST",
"path": "/services/xxx",
"body": "{\"text\": \"High error count: {{ctx.payload.hits.total.value}} errors in 5m\"}"
}
}
}
}
Anti-Patterns
- Capturing request bodies in production - Setting
captureBody: 'all'leaks sensitive data; use'errors'or'off'in production. - Missing log correlation - Without injecting trace IDs into logs, you cannot jump from a trace to its log lines in Kibana.
- Single-node Elasticsearch in production - Always run a cluster with replicas; a single node loses data on failure.
- Not filtering health checks - Synthetic health checks pollute APM transaction data and skew latency metrics.
When to Use
- You already use Elasticsearch and Kibana for logging and want APM in the same stack.
- You need service maps and dependency visualization for microservice architectures.
- You want trace-log correlation without maintaining separate systems.
- You need self-hosted observability with full control over data retention.
- You are running the Elastic Stack on Kubernetes with ECK (Elastic Cloud on Kubernetes).
Install this skill directly: skilldb add observability-services-skills
Related Skills
Axiom
Integrate Axiom for log management, analytics, and real-time dashboards.
Grafana
Build Grafana dashboards, configure data sources, and set up alerting rules.
Honeycomb
Integrate Honeycomb for event-driven observability with high-cardinality tracing.
Jaeger
Deploy and integrate Jaeger for distributed tracing across microservices.
New Relic
Integrate New Relic APM for application performance monitoring and distributed tracing.
Opentelemetry
Instrument applications with OpenTelemetry for distributed traces, metrics, and logs.