Common Patterns
Production-tested patterns for every major combination of framework, database, and exporter.
1. Express + MongoDB
typescript
import express from 'express';
import mongoose from 'mongoose';
import { createMonitor, expressContext, mongooseAdapter } from '@periodic/arsenic';
const app = express();
const monitor = createMonitor({
slowQueryThresholdMs: 200,
exporter: (event) => {
if (event.severity === 'critical') sendToPagerDuty(event);
else if (event.severity === 'warning') sendToSlack(event);
else logger.info(event);
},
});
app.use(expressContext(monitor));
mongooseAdapter(monitor, mongoose);
app.listen(3000);2. Express + PostgreSQL
typescript
import express from 'express';
import { Pool } from 'pg';
import { createMonitor, expressContext, pgAdapter } from '@periodic/arsenic';
const app = express();
const pool = new Pool({ host: process.env.POSTGRES_HOST });
const monitor = createMonitor({
slowQueryThresholdMs: 150,
exporter: (event) => { if (event.severity === 'critical') sendToSlack(event); },
});
app.use(expressContext(monitor));
pgAdapter(monitor, pool);
app.listen(3000);3. Fastify + Prisma
typescript
import Fastify from 'fastify';
import { PrismaClient } from '@prisma/client';
import { createMonitor, fastifyContext, prismaAdapter } from '@periodic/arsenic';
const app = Fastify();
const prisma = new PrismaClient();
const monitor = createMonitor({
slowQueryThresholdMs: 200,
exporter: (event) => logger.info(event),
});
await app.register(fastifyContext(monitor, { attachUser: (req) => req.user?.id }));
prismaAdapter(monitor, prisma);
await app.listen({ port: 3000 });4. OpenTelemetry exporter
typescript
import { createMonitor, createOtelExporter } from '@periodic/arsenic';
const monitor = createMonitor({
exporter: createOtelExporter({
serviceName: process.env.SERVICE_NAME || 'my-service',
exportAsSpans: true,
exportAsMetrics: true,
}),
});5. Multiple databases, separate monitors
typescript
const pgMonitor = createMonitor({
slowQueryThresholdMs: 100, // Stricter for SQL
exporter: pgExporter,
});
const mongoMonitor = createMonitor({
slowQueryThresholdMs: 300, // Looser for MongoDB
exporter: mongoExporter,
});
const redisMonitor = createMonitor({
slowQueryThresholdMs: 50, // Very strict for Redis
exporter: redisExporter,
});
pgAdapter(pgMonitor, pool);
mongooseAdapter(mongoMonitor, mongoose);
redisAdapter(redisMonitor, redis);6. Multiple exporters
typescript
const monitor = createMonitor({
exporter: async (event) => {
await Promise.allSettled([
console.log(event),
sendToDatadog(event),
saveToDB(event),
]);
},
});7. Production configuration
src/config/monitor.ts
typescript
import { createMonitor, SignalSeverity } from '@periodic/arsenic';
const isDev = process.env.NODE_ENV === 'development';
export const monitor = createMonitor({
slowQueryThresholdMs: isDev ? 500 : 200,
emitPositiveSignals: isDev,
includeDocs: isDev,
exporter: async (event) => {
logger.info(event, 'db.event');
if (!isDev && event.severity === SignalSeverity.CRITICAL) {
await sendToPagerDuty(event);
}
if (event.severity === SignalSeverity.WARNING) {
await sendToSlack(event);
}
},
});
export default monitor;Rate limit your exporter
In high-traffic systems, add rate limiting to your exporter to avoid flooding PagerDuty or Slack. Use
Promise.allSettled so a slow exporter never blocks your app.