Structured Logging
Send structured logs from your application using the SDK logger.
Overview#
The JustAnalytics SDK provides a built-in structured logger that automatically correlates logs with traces and sends them to the Log Explorer.
Using the Logger#
Basic Usage#
import JA from '@justanalyticsapp/node';
JA.init({
siteId: 'YOUR_SITE_ID',
apiKey: 'YOUR_API_KEY',
serviceName: 'api-server',
});
// Log at different levels
JA.logger.debug('Detailed debug information', { query: sql });
JA.logger.info('User logged in', { userId: 'user_123' });
JA.logger.warn('Slow query detected', { duration_ms: 2500, table: 'orders' });
JA.logger.error('Payment failed', { orderId: '456', reason: 'card_declined' });
JA.logger.fatal('Database connection lost', { host: 'db.example.com' });
Structured Context#
Always include structured data as the second argument:
// Good: structured context
JA.logger.info('Order processed', {
orderId: 'ord_123',
total: 149.99,
items: 3,
duration_ms: 245,
});
// Avoid: embedding data in the message
JA.logger.info('Order ord_123 processed for $149.99 with 3 items in 245ms');
Integration with Winston#
Use the Winston transport to send logs from existing Winston-based applications:
import winston from 'winston';
import { createWinstonTransport } from '@justanalyticsapp/node/winston';
const logger = winston.createLogger({
level: 'info',
transports: [
new winston.transports.Console(),
createWinstonTransport(), // Sends logs to JustAnalytics
],
});
logger.info('Server started', { port: 3000 });
Integration with Pino#
Use the Pino transport for Pino-based applications:
import pino from 'pino';
import { createPinoTransport } from '@justanalyticsapp/node/pino';
const logger = pino({
transport: {
targets: [
{ target: 'pino-pretty' },
createPinoTransport(), // Sends logs to JustAnalytics
],
},
});
logger.info({ userId: 'user_123' }, 'User logged in');
Automatic Trace Correlation#
When logs are emitted inside a startSpan callback, the trace ID and span ID are automatically attached:
JA.startSpan('handle-request', async (span) => {
JA.logger.info('Request received', { path: '/api/orders' });
// This log includes: traceId, spanId, serviceName
const orders = await JA.startSpan('db.query', async () => {
JA.logger.debug('Querying orders table');
// This log includes the child span's ID
return await db.orders.findMany();
});
JA.logger.info('Request completed', { orderCount: orders.length });
});
Log Format#
Logs sent to JustAnalytics follow this format:
{
"timestamp": "2024-03-15T10:30:00.000Z",
"level": "info",
"message": "Order processed",
"service": "api-server",
"environment": "production",
"traceId": "abc123def456",
"spanId": "789ghi",
"context": {
"orderId": "ord_123",
"total": 149.99
}
}
Best Practices#
- Use structured context -- pass data as objects, not embedded in strings
- Use appropriate levels -- debug for verbose info, error for actual errors
- Include identifiers -- always include relevant IDs (userId, orderId, etc.)
- Be consistent -- use the same field names across your application
- Avoid sensitive data -- never log passwords, tokens, or PII