@statly/observe
v1.2.1
Published
JavaScript SDK for Statly Observe - Error tracking and monitoring
Downloads
738
Maintainers
Readme
Statly Observe SDK for Node.js
Error tracking and monitoring for JavaScript and TypeScript applications. Capture exceptions, track releases, and debug issues faster.
📚 Full Documentation | 🚀 Get Started | 💬 Support
This SDK requires a Statly account. Sign up free at statly.live to get your DSN and start tracking errors in minutes.
Features
- Automatic error capturing with stack traces
- Structured Logging: Production-grade logging with automatic scrubbing
- Distributed Tracing: Visualize function execution and call hierarchies
- Performance Metrics: Automated capture of latency and success rates
- Breadcrumbs for debugging context
- User context tracking
- Release tracking
- Framework integrations (Express, Next.js, Fastify)
- TypeScript support
- Minimal overhead
Installation
npm install @statly/observe
# or
yarn add @statly/observe
# or
pnpm add @statly/observeGetting Your DSN
- Go to statly.live/dashboard/observe/setup
- Create an API key for Observe
- Copy your DSN (format:
https://<key-prefix>@statly.live/<org-slug>) - Add to your
.envfile:STATLY_DSN=https://...
Note: The DSN contains only a 16-character key prefix (e.g., sk_live_a1b2c3d4) which is safe to embed in client-side code. For server-side operations requiring full permissions, use the complete API key.
Quick Start
The SDK automatically loads DSN from environment variables, so you can simply:
import { Statly } from '@statly/observe';
// Auto-loads STATLY_DSN from environment
Statly.init();Or pass it explicitly:
import { Statly } from '@statly/observe';
// Initialize the SDK
Statly.init({
dsn: 'https://[email protected]/your-org',
release: '1.0.0',
environment: 'production',
});
// Errors are captured automatically via global handlers
// Manual capture
try {
riskyOperation();
} catch (error) {
Statly.captureException(error);
}
// Capture a message
Statly.captureMessage('User completed checkout', 'info');
// Set user context
Statly.setUser({
id: 'user-123',
email: '[email protected]',
});
// Add breadcrumb for debugging
Statly.addBreadcrumb({
category: 'auth',
message: 'User logged in',
level: 'info',
});
# Flush before exit (important for serverless)
await Statly.close();Tracing & Performance
Statly Observe supports distributed tracing to help you visualize execution flow and measure backend performance.
Automatic Tracing
Use Statly.trace() to wrap functions. It works with both synchronous and asynchronous code:
import { Statly } from '@statly/observe';
const result = await Statly.trace('process_payment', async (span) => {
span.setTag('provider', 'stripe');
// Your logic here
const payment = await stripe.charges.create({...});
return payment;
});Manual Spans
For low-level control, you can start spans manually:
const span = Statly.startSpan('database_query');
try {
await db.query('...');
span.setTag('query_type', 'SELECT');
} finally {
span.finish(); // Reports to Statly
}Structured Logging
The Logger class provides production-grade structured logging with automatic secret scrubbing, session management, and batching.
Quick Start
import { Logger } from '@statly/observe';
const logger = Logger.create({
dsn: 'https://[email protected]/your-org',
environment: 'production',
loggerName: 'api-server',
});
// Log at different levels
logger.trace('Entering function', { args: [1, 2, 3] });
logger.debug('Processing request', { requestId: 'req_123' });
logger.info('User logged in', { userId: 'user_123' });
logger.warn('Rate limit approaching', { current: 95, limit: 100 });
logger.error('Payment failed', { orderId: 'ord_456', error: 'Card declined' });
logger.fatal('Database connection lost', { host: 'db.example.com' });
logger.audit('User role changed', { userId: 'user_123', newRole: 'admin' });
// Always close before exit
await logger.close();Child Loggers
Create child loggers with inherited context:
const requestLogger = logger.child({
context: { requestId: 'req_123' },
loggerName: 'request-handler',
});
requestLogger.info('Processing request'); // Includes requestId automaticallyUser Context
Associate logs with users:
logger.setUser({
id: 'user_123',
email: '[email protected]',
name: 'Jane Doe',
});Secret Scrubbing
The logger automatically scrubs sensitive data (API keys, passwords, credit cards, etc.). Add custom patterns:
const logger = Logger.create({
dsn: '...',
scrubPatterns: [
/my-custom-secret-[a-z0-9]+/gi,
/internal-token-\d+/g,
],
});Sample Rates
Control log volume with per-level sampling:
const logger = Logger.create({
dsn: '...',
sampleRates: {
trace: 0.01, // 1% of trace logs
debug: 0.1, // 10% of debug logs
info: 0.5, // 50% of info logs
warn: 1.0, // 100% of warnings
error: 1.0, // 100% of errors
fatal: 1.0, // 100% of fatal
},
});Logger Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| dsn | string | required | Your project's Data Source Name |
| environment | string | undefined | Environment name |
| release | string | undefined | Release/version identifier |
| loggerName | string | undefined | Logger name for filtering |
| sessionId | string | auto-generated | Session ID for grouping logs |
| user | object | undefined | User context |
| defaultContext | object | {} | Default context for all logs |
| minLevel | LogLevel | 'trace' | Minimum level to log |
| sampleRates | object | all 1.0 | Per-level sample rates |
| scrubPatterns | RegExp[] | [] | Additional patterns to scrub |
| batchSize | number | 50 | Batch size before flush |
| flushInterval | number | 5000 | Flush interval in ms |
| maxQueueSize | number | 1000 | Max queue size |
Framework Integrations
Express
import express from 'express';
import { Statly, requestHandler, expressErrorHandler } from '@statly/observe';
const app = express();
// Initialize first
Statly.init({
dsn: 'https://[email protected]/your-org',
environment: process.env.NODE_ENV,
});
// Add request handler FIRST (before routes)
app.use(requestHandler());
// Your routes
app.get('/', (req, res) => {
res.send('Hello World');
});
app.get('/error', (req, res) => {
throw new Error('Test error');
});
// Add error handler LAST (after routes)
app.use(expressErrorHandler());
app.listen(3000);Next.js (App Router)
Route Handlers:
// app/api/example/route.ts
import { withStatly } from '@statly/observe';
export const GET = withStatly(async (request) => {
// Errors are automatically captured
const data = await fetchData();
return Response.json({ data });
});Error Boundary:
// app/error.tsx
'use client';
import { useEffect } from 'react';
import { captureNextJsError } from '@statly/observe';
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
captureNextJsError(error);
}, [error]);
return (
<div>
<h2>Something went wrong!</h2>
<button onClick={reset}>Try again</button>
</div>
);
}Server Actions:
'use server';
import { withStatlyServerAction } from '@statly/observe';
export const submitForm = withStatlyServerAction(
async (formData: FormData) => {
// Your action code - errors are captured automatically
const email = formData.get('email');
await saveToDatabase(email);
},
'submitForm' // Action name for grouping
);Fastify
import Fastify from 'fastify';
import { Statly, statlyFastifyPlugin } from '@statly/observe';
const fastify = Fastify();
Statly.init({
dsn: 'https://[email protected]/your-org',
});
// Register the plugin
fastify.register(statlyFastifyPlugin, {
captureValidationErrors: true,
skipStatusCodes: [400, 401, 403, 404], // Don't capture these as errors
});
fastify.get('/', async () => {
return { hello: 'world' };
});
fastify.listen({ port: 3000 });Environment Variables
The SDK automatically loads configuration from environment variables:
| Variable | Description |
|----------|-------------|
| STATLY_DSN | Your project's DSN (primary) |
| NEXT_PUBLIC_STATLY_DSN | DSN for Next.js client-side |
| STATLY_OBSERVE_DSN | Alternative DSN variable |
| STATLY_ENVIRONMENT | Environment name |
| NODE_ENV | Fallback for environment |
Configuration Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| dsn | string | process.env.STATLY_DSN | Your project's Data Source Name |
| environment | string | undefined | Environment name (production, staging, development) |
| release | string | undefined | Release/version identifier for tracking |
| debug | boolean | false | Enable debug logging to console |
| sampleRate | number | 1.0 | Sample rate for events (0.0 to 1.0) |
| maxBreadcrumbs | number | 100 | Maximum breadcrumbs to store |
| autoCapture | boolean | true | Auto-attach global error handlers |
| beforeSend | function | undefined | Callback to modify/filter events before sending |
beforeSend Example
Statly.init({
dsn: '...',
beforeSend: (event) => {
// Filter out specific errors
if (event.message?.includes('ResizeObserver')) {
return null; // Drop the event
}
// Scrub sensitive data
if (event.extra?.password) {
delete event.extra.password;
}
return event;
},
});API Reference
Statly.captureException(error, context?)
Capture an exception with optional additional context:
try {
await processPayment(order);
} catch (error) {
Statly.captureException(error, {
extra: {
orderId: order.id,
amount: order.total,
},
tags: {
paymentProvider: 'stripe',
},
});
}Statly.captureMessage(message, level?)
Capture a message event:
Statly.captureMessage('User signed up', 'info');
Statly.captureMessage('Payment failed after 3 retries', 'warning');
Statly.captureMessage('Database connection lost', 'error');Levels: 'debug' | 'info' | 'warning' | 'error' | 'fatal'
Statly.setUser(user)
Set user context for all subsequent events:
Statly.setUser({
id: 'user-123',
email: '[email protected]',
username: 'johndoe',
// Custom fields
subscription: 'premium',
});
// Clear user on logout
Statly.setUser(null);Statly.setTag(key, value) / Statly.setTags(tags)
Set tags for filtering and searching:
Statly.setTag('version', '1.0.0');
Statly.setTags({
environment: 'production',
server: 'web-1',
region: 'us-east-1',
});Statly.addBreadcrumb(breadcrumb)
Add a breadcrumb for debugging context:
Statly.addBreadcrumb({
message: 'User clicked checkout button',
category: 'ui.click',
level: 'info',
data: {
buttonId: 'checkout-btn',
cartItems: 3,
},
});Statly.flush() / Statly.close()
// Flush pending events (keeps SDK running)
await Statly.flush();
// Flush and close (use before process exit)
await Statly.close();TypeScript Support
Full TypeScript support with exported types:
import type {
StatlyOptions,
StatlyEvent,
User,
Breadcrumb,
EventLevel,
} from '@statly/observe';Requirements
- Node.js 16+
- Works in browser environments (with bundler)
Resources
- Statly Platform - Sign up and manage your error tracking
- Documentation - Full SDK documentation
- API Reference - Complete API reference
- Express Guide - Express integration
- Next.js Guide - Next.js integration
- Fastify Guide - Fastify integration
- MCP Server - AI/Claude integration for docs
Why Statly?
Statly is more than error tracking. Get:
- Status Pages - Beautiful public status pages for your users
- Uptime Monitoring - Multi-region HTTP/DNS checks every minute
- Error Tracking - SDKs for JavaScript, Python, and Go
- Incident Management - Track and communicate outages
All on Cloudflare's global edge network. Start free →
License
MIT
