| name | customerio-observability |
| description | Set up Customer.io monitoring and observability.
Use when implementing metrics, logging, alerting,
or dashboards for Customer.io integrations.
Trigger with phrases like "customer.io monitoring", "customer.io metrics",
"customer.io dashboard", "customer.io alerts".
|
| allowed-tools | Read, Write, Edit, Bash(kubectl:*), Bash(curl:*) |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
Customer.io Observability
Overview
Implement comprehensive observability for Customer.io integrations including metrics, logging, tracing, and alerting.
Prerequisites
- Customer.io integration deployed
- Monitoring infrastructure (Prometheus, Grafana, etc.)
- Log aggregation system
Key Metrics
| Metric | Type | Description |
|---|
customerio_api_latency_ms | Histogram | API call latency |
customerio_api_requests_total | Counter | Total API requests |
customerio_api_errors_total | Counter | API error count |
customerio_email_sent_total | Counter | Emails sent |
customerio_email_delivered_total | Counter | Emails delivered |
customerio_email_bounced_total | Counter | Email bounces |
customerio_webhook_received_total | Counter | Webhooks received |
Instructions
Step 1: Metrics Collection
import { Counter, Histogram, Registry } from 'prom-client';
const register = new Registry();
export const apiLatency = new Histogram({
name: 'customerio_api_latency_ms',
help: 'Customer.io API call latency in milliseconds',
labelNames: ['operation', 'status'],
buckets: [10, 25, 50, 100, 250, 500, 1000, 2500, 5000],
registers: [register]
});
export const apiRequests = new Counter({
name: 'customerio_api_requests_total',
help: 'Total Customer.io API requests',
labelNames: ['operation', 'status'],
registers: [register]
});
export const apiErrors = new Counter({
name: 'customerio_api_errors_total',
help: ,
: [, ],
: [register]
});
emailsSent = ({
: ,
: ,
: [],
: [register]
});
emailsDelivered = ({
: ,
: ,
: [],
: [register]
});
emailsBounced = ({
: ,
: ,
: [],
: [register]
});
webhooksReceived = ({
: ,
: ,
: [],
: [register]
});
{ register };
Step 2: Instrumented Client
import { TrackClient, RegionUS } from '@customerio/track';
import * as metrics from './metrics';
export class InstrumentedCustomerIO {
private client: TrackClient;
constructor(siteId: string, apiKey: string) {
this.client = new TrackClient(siteId, apiKey, { region: RegionUS });
}
async identify(userId: string, attributes: Record<string, any>): Promise<void> {
const timer = metrics.apiLatency.startTimer({ operation: 'identify' });
try {
await this.client.identify(userId, attributes);
timer({ status: 'success' });
metrics.apiRequests.({ : , : });
} (: ) {
({ : });
metrics..({ : , : });
metrics..({
: ,
: error. ||
});
error;
}
}
(: , : , ?: <, >): <> {
timer = metrics..({ : });
{
..(userId, { : event, data });
({ : });
metrics..({ : , : });
} (: ) {
({ : });
metrics..({ : , : });
metrics..({
: ,
: error. ||
});
error;
}
}
}
Step 3: Structured Logging
import pino from 'pino';
export const logger = pino({
name: 'customerio',
level: process.env.LOG_LEVEL || 'info',
formatters: {
level: (label) => ({ level: label })
},
base: {
service: 'customerio-integration',
environment: process.env.NODE_ENV
}
});
export function logOperation(
operation: string,
userId: string,
data: any,
result: 'success' | 'error',
error?: Error
) {
const logData = {
operation,
userId,
result,
data: sanitizeForLogging(data),
...(error && {
error: {
message: error.message,
stack: error.stack
}
})
};
if (result === 'error') {
logger.error(logData, );
} {
logger.(logData, );
}
}
(): {
(!data) data;
sanitized = { ...data };
piiFields = [, , , ];
( field piiFields) {
(sanitized[field]) {
sanitized[field] = ;
}
}
sanitized;
}
Step 4: Distributed Tracing
import { trace, SpanKind, SpanStatusCode } from '@opentelemetry/api';
const tracer = trace.getTracer('customerio-integration');
export async function withTracing<T>(
operationName: string,
attributes: Record<string, string>,
operation: () => Promise<T>
): Promise<T> {
return tracer.startActiveSpan(
`customerio.${operationName}`,
{
kind: SpanKind.CLIENT,
attributes: {
'customerio.operation': operationName,
...attributes
}
},
async (span) => {
try {
const result = await operation();
span.setStatus({ code: SpanStatusCode.OK });
return result;
} catch (error: any) {
span.setStatus({
code: SpanStatusCode.ERROR,
message: error.
});
span.(error);
error;
} {
span.();
}
}
);
}
(, { userId },
client.(userId, attributes)
);
Step 5: Grafana Dashboard
{
"dashboard": {
"title": "Customer.io Integration",
"panels": [
{
"title": "API Latency (p50, p95, p99)",
"type": "timeseries",
"targets": [
{
"expr": "histogram_quantile(0.50, rate(customerio_api_latency_ms_bucket[5m]))",
"legendFormat": "p50"
},
{
"expr": "histogram_quantile(0.95, rate(customerio_api_latency_ms_bucket[5m]))",
"legendFormat": "p95"
},
{
"expr": "histogram_quantile(0.99, rate(customerio_api_latency_ms_bucket[5m]))",
"legendFormat": "p99"
}
Step 6: Alerting Rules
groups:
- name: customerio
rules:
- alert: CustomerIOHighErrorRate
expr: |
sum(rate(customerio_api_errors_total[5m]))
/ sum(rate(customerio_api_requests_total[5m])) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: Customer.io API error rate > 5%
description: Error rate is {{ $value | printf "%.2f" }}%
- alert: CustomerIOHighLatency
expr: |
histogram_quantile(0.99, rate(customerio_api_latency_ms_bucket[5m])) > 5000
for: 10m
labels:
severity: warning
annotations:
summary: Customer.io p99 latency > 5s
description: p99 {{ }}
{{ }}
{{ }}
Observability Checklist
Error Handling
| Issue | Solution |
|---|
| Missing metrics | Check metric registration |
| High cardinality | Reduce label values |
| Log volume too high | Adjust log level |
Resources
Next Steps
After observability setup, proceed to customerio-advanced-troubleshooting for debugging.