Sentry supports sending structured logs and custom metrics alongside your error and performance data, providing a complete observability solution.
Logs
Sentry logs provide structured, searchable logging with automatic correlation to traces and errors.
Setup
Enable logs in your SDK initialization:
import * as Sentry from '@sentry/node';
Sentry.init({
dsn: 'your-dsn',
// Enable logs
enableLogs: true,
// Configure log levels
logLevel: 'info', // minimum level to capture
});
Capturing Logs
Use the logger API to send structured logs:
import * as Sentry from '@sentry/node';
// Different log levels
Sentry.logger.trace('Detailed trace information');
Sentry.logger.debug('Debug information', { component: 'UserService' });
Sentry.logger.info('User logged in', { userId: '123' });
Sentry.logger.warn('Deprecated API used', { endpoint: '/old-api' });
Sentry.logger.error('Operation failed', { error: 'Connection timeout' });
Sentry.logger.fatal('Critical system failure', { service: 'database' });
Logs require the enableLogs option to be set to true during initialization.
Log Attributes
Add structured data to logs:
Sentry.logger.info('User action', {
user_id: '123',
action: 'purchase',
product_id: 'prod-456',
amount: 99.99,
currency: 'USD',
payment_method: 'credit_card'
});
Template Strings
Use template strings for structured logging:
import * as Sentry from '@sentry/node';
const userId = '123';
const page = '/dashboard';
// Parameterized log message
Sentry.logger.info(
Sentry.logger.fmt`User ${userId} navigated to ${page}`,
{
userId: '123',
sessionId: 'abc-xyz'
}
);
Template strings allow Sentry to group similar log messages together while preserving the actual values.
Log with Scope
Capture logs with specific scope:
import { getCurrentScope } from '@sentry/node';
const scope = getCurrentScope();
scope.setTag('service', 'payment');
Sentry.logger.info('Payment processed', {
order_id: '123',
amount: 99.99
}, {
scope // Use this specific scope
});
Log Levels
- trace: Very detailed diagnostic information
- debug: Detailed information for debugging
- info: General informational messages
- warn: Warning messages for potentially harmful situations
- error: Error events
- fatal: Very severe error events that might lead to application abort
Metrics
Custom metrics help you track business and technical KPIs.
Counters
Increment counters for counting events:
import * as Sentry from '@sentry/node';
// Increment by 1
Sentry.metrics.count('api.requests', 1, {
attributes: {
endpoint: '/api/users',
method: 'GET',
status: 200
}
});
// Increment by custom value
Sentry.metrics.count('items.processed', 5, {
attributes: {
processor: 'batch-1',
queue: 'high-priority'
}
});
Gauges
Record current values:
// Memory usage
Sentry.metrics.gauge('memory.usage', 1024, {
unit: 'megabyte',
attributes: {
process: 'web-server',
region: 'us-east-1'
}
});
// Active connections
Sentry.metrics.gauge('connections.active', 42, {
attributes: {
server: 'api-1',
protocol: 'websocket'
}
});
// Queue depth
Sentry.metrics.gauge('queue.depth', 150, {
unit: 'item',
attributes: {
queue: 'email-notifications'
}
});
Distributions
Record value distributions for statistical analysis:
// Request duration
Sentry.metrics.distribution('request.duration', 245, {
unit: 'millisecond',
attributes: {
endpoint: '/api/users',
method: 'GET'
}
});
// Response size
Sentry.metrics.distribution('response.size', 1024, {
unit: 'byte',
attributes: {
endpoint: '/api/data',
compression: 'gzip'
}
});
// Batch size
Sentry.metrics.distribution('batch.size', 100, {
attributes: {
processor: 'data-pipeline',
type: 'async'
}
});
Metric Units
Use standard units for better visualization:
// Time units
Sentry.metrics.distribution('duration', 500, { unit: 'millisecond' });
Sentry.metrics.distribution('latency', 1.5, { unit: 'second' });
// Size units
Sentry.metrics.gauge('memory', 512, { unit: 'megabyte' });
Sentry.metrics.distribution('payload', 1024, { unit: 'byte' });
// Custom units
Sentry.metrics.gauge('temperature', 72, { unit: 'fahrenheit' });
Sentry.metrics.count('requests', 100, { unit: 'request' });
Correlation with Traces
Logs and metrics are automatically correlated with active spans:
import * as Sentry from '@sentry/node';
Sentry.startSpan({ name: 'process_order', op: 'function' }, () => {
// Log is automatically linked to span
Sentry.logger.info('Processing order', { orderId: '123' });
// Metric is linked to trace
Sentry.metrics.count('orders.processed', 1, {
attributes: { status: 'success' }
});
processOrder();
});
Logs and metrics captured within a span are automatically tagged with the trace ID and span ID.
Practical Examples
API Monitoring
import * as Sentry from '@sentry/node';
import express from 'express';
const app = express();
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
// Log request
Sentry.logger.info(
Sentry.logger.fmt`${req.method} ${req.path}`,
{
method: req.method,
path: req.path,
status: res.statusCode,
duration
}
);
// Count requests
Sentry.metrics.count('api.requests', 1, {
attributes: {
method: req.method,
endpoint: req.route?.path || req.path,
status: res.statusCode
}
});
// Track duration
Sentry.metrics.distribution('api.duration', duration, {
unit: 'millisecond',
attributes: {
endpoint: req.route?.path || req.path
}
});
});
next();
});
Database Operations
import * as Sentry from '@sentry/node';
async function queryDatabase(sql, params) {
const start = Date.now();
try {
const result = await db.query(sql, params);
const duration = Date.now() - start;
// Log successful query
Sentry.logger.debug('Database query executed', {
query: sql,
rows: result.rowCount,
duration
});
// Track query count
Sentry.metrics.count('db.queries', 1, {
attributes: {
operation: getOperationType(sql),
status: 'success'
}
});
// Track query duration
Sentry.metrics.distribution('db.query.duration', duration, {
unit: 'millisecond',
attributes: {
operation: getOperationType(sql)
}
});
return result;
} catch (error) {
// Log error
Sentry.logger.error('Database query failed', {
query: sql,
error: error.message
});
// Count errors
Sentry.metrics.count('db.errors', 1, {
attributes: {
error_type: error.code
}
});
throw error;
}
}
Business Metrics
import * as Sentry from '@sentry/node';
async function processOrder(order) {
Sentry.logger.info('Processing order', {
order_id: order.id,
user_id: order.userId,
amount: order.total
});
// Count orders
Sentry.metrics.count('orders.processed', 1, {
attributes: {
payment_method: order.paymentMethod,
country: order.shippingAddress.country
}
});
// Track order value
Sentry.metrics.distribution('order.value', order.total, {
unit: 'dollar',
attributes: {
currency: order.currency,
payment_method: order.paymentMethod
}
});
// Track order items
Sentry.metrics.distribution('order.items', order.items.length, {
unit: 'item'
});
await saveOrder(order);
}
Resource Monitoring
import * as Sentry from '@sentry/node';
import os from 'os';
// Monitor system resources
setInterval(() => {
const memUsage = process.memoryUsage();
const cpuUsage = process.cpuUsage();
// Memory metrics
Sentry.metrics.gauge('memory.heap_used', memUsage.heapUsed, {
unit: 'byte'
});
Sentry.metrics.gauge('memory.heap_total', memUsage.heapTotal, {
unit: 'byte'
});
// CPU metrics
Sentry.metrics.gauge('cpu.user', cpuUsage.user, {
unit: 'microsecond'
});
Sentry.metrics.gauge('cpu.system', cpuUsage.system, {
unit: 'microsecond'
});
// Log if memory is high
if (memUsage.heapUsed / memUsage.heapTotal > 0.9) {
Sentry.logger.warn('High memory usage', {
heap_used: memUsage.heapUsed,
heap_total: memUsage.heapTotal,
percentage: Math.round((memUsage.heapUsed / memUsage.heapTotal) * 100)
});
}
}, 60000); // Every minute
Error Rate Tracking
import * as Sentry from '@sentry/node';
function trackOperationResult(operation, success) {
// Log the operation
Sentry.logger.info('Operation completed', {
operation,
success
});
// Count successes and failures
Sentry.metrics.count('operations', 1, {
attributes: {
operation,
status: success ? 'success' : 'failure'
}
});
}
try {
await criticalOperation();
trackOperationResult('critical_operation', true);
} catch (error) {
trackOperationResult('critical_operation', false);
Sentry.captureException(error);
}
Scope Integration
Logs and metrics respect scope attributes:
import { getCurrentScope } from '@sentry/node';
const scope = getCurrentScope();
scope.setAttributes({
service: 'api',
environment: 'production',
region: 'us-east-1'
});
// These attributes are automatically added to logs and metrics
Sentry.logger.info('Service started');
Sentry.metrics.gauge('service.uptime', 3600, { unit: 'second' });
Best Practices
Logs
- Use appropriate levels: Match severity to importance
- Add context: Include relevant attributes
- Use structured data: Avoid string concatenation
- Avoid sensitive data: Don’t log PII or secrets
- Use templates: For better grouping
// Good: Structured with attributes
Sentry.logger.info('User action', {
user_id: '123',
action: 'purchase'
});
// Bad: String concatenation
Sentry.logger.info(`User 123 made a purchase`);
Metrics
- Choose the right type: Counter, gauge, or distribution
- Use consistent names: Follow naming conventions
- Add relevant attributes: For filtering and grouping
- Use standard units: For better visualization
- Don’t over-instrument: Focus on meaningful metrics
// Good: Clear name, appropriate type, useful attributes
Sentry.metrics.distribution('api.response_time', duration, {
unit: 'millisecond',
attributes: {
endpoint: '/api/users',
method: 'GET'
}
});
// Bad: Vague name, no attributes
Sentry.metrics.gauge('time', duration);
Viewing Logs and Metrics
In Sentry:
- Logs Explorer: Search and filter logs
- Metrics Dashboard: Visualize custom metrics
- Trace View: See logs/metrics within traces
- Correlation: Link logs/metrics to errors
Next Steps
Performance
Monitor application performance
Tracing
Correlate logs with traces
Error Monitoring
Link errors with logs
Scopes
Manage scope attributes