Skip to content

Node.js SDK ​

The Node.js SDK provides server-side logging for Node.js applications. Built on top of logstyx-js-core, it adds automatic device information collection, optional error capture, and automatic HTTP request logging for production environments.

Installation ​

bash
npm install github:devatlogstyx/logstyx-js-node#release

Requirements

Node.js version 18 or higher is required.

Quick Start ​

Manual Logging (Traditional) ​

javascript
const logstyx = require('logstyx-js-node')({
  projectId: 'YOUR_PROJECT_ID',
  apiKey: 'YOUR_API_KEY'
});

// Log events manually
logstyx.info({ message: 'User logged in', userId: 123 });
logstyx.error({ message: 'Payment failed', error: err.message });

Auto-Instrumentation (Zero-Code Logging) ​

Automatically log all HTTP requests without manual logstyx.info() calls:

javascript
const logstyx = require('logstyx-js-node')({
  projectId: 'YOUR_PROJECT_ID',
  apiKey: 'YOUR_API_KEY',
  autoInstrument: true  // 🔥 Enable automatic logging
});

const express = require('express');
const app = express();

app.get('/api/orders', (req, res) => {
  res.json({ orders: [] });
  // ✅ Automatically logged: method, path, status, duration
});

app.listen(3000);

No manual logging needed! All requests are automatically captured.

Configuration Options ​

Required Options ​

projectId (string) ​

Your Logstyx project identifier from the dashboard.

javascript
projectId: 'proj_abc123xyz'

apiKey (string) ​

Your project's API key for HMAC signature authentication. Get this from your project settings.

javascript
apiKey: 'your_api_key_here'

Keep API Keys Secret

Never commit API keys to version control or expose them in client-side code. Use environment variables:

javascript
apiKey: process.env.LOGSTYX_API_KEY

Optional Options ​

endpoint (string) ​

The Logstyx API endpoint, should point to your self-hosted instance.

Default: https://api.logstyx.com/v1/logs

javascript
endpoint: 'https://logs.yourcompany.com/api/v1/logs'

captureUncaught (boolean) ​

Enable automatic capture of uncaught exceptions. When enabled, uncaught errors are logged as critical before the process exits.

Default: false

javascript
captureUncaught: true

captureUnhandledRejections (boolean) ​

Enable automatic capture of unhandled promise rejections. When enabled, unhandled rejections are logged as critical.

Default: false

javascript
captureUnhandledRejections: true

autoInstrument (boolean) ​

Enable automatic HTTP request logging. When enabled, all HTTP requests are automatically logged with method, path, status, duration, and more.

Default: false

javascript
autoInstrument: true

ignorePaths (string[]) ​

Array of paths to ignore when auto-instrumentation is enabled. Useful for health checks and metrics endpoints.

Default: ['/health', '/metrics']

javascript
ignorePaths: ['/health', '/metrics', '/favicon.ico']

slowRequestThreshold (number) ​

Duration in milliseconds. Requests exceeding this threshold will be logged as WARNING instead of INFO.

Default: 1000 (1 second)

javascript
slowRequestThreshold: 2000  // 2 seconds

redactFields (string[]) ​

Array of field names to redact from request/response bodies and headers. Field values are replaced with [REDACTED].

Default: ['password', 'token', 'authorization', 'secret', 'apiKey', 'creditCard', 'ssn']

javascript
redactFields: ['password', 'token', 'authorization', 'secret', 'apiKey']

contextHook (function) ​

Function that receives the Express/Fastify request object and returns additional context to include in every auto-logged request.

Default: null

javascript
contextHook: (req) => ({
  tenantId: req.headers['x-tenant-id'],
  environment: process.env.NODE_ENV,
  version: process.env.APP_VERSION
})

buildRequestPayload (function) ​

Custom function to build the request payload. Receives the request object and should return an object with the data you want to log.

Default: Built-in payload builder

javascript
buildRequestPayload: (req) => ({
  method: req.method,
  path: req.path,
  ip: req.ip,
  userId: req.user?.id
})

Manual Logging ​

Perfect for logging custom business events, database operations, or any application-specific events.

Basic Usage ​

javascript
const logstyx = require('logstyx-js-node')({
  projectId: 'YOUR_PROJECT_ID',
  apiKey: 'YOUR_API_KEY',
  endpoint: 'https://api.logstyx.com/v1/logs',
  captureUncaught: true,
  captureUnhandledRejections: true
});

// Send logs at different levels
logstyx.info({ message: 'This is an info log!' });
logstyx.warning({ message: 'This is a warning log!' });
logstyx.error({ message: 'This is an error log!' });
logstyx.critical({ message: 'System failure!' });

Setting Context ​

Add persistent context that will be included in all subsequent logs:

javascript
// Add persistent context
logstyx.setContext({ 
  userId: 123, 
  environment: 'production' 
});

// All subsequent logs will include this context
logstyx.info({ message: 'User action' }); 
// Includes userId and environment

// Clear context when needed
logstyx.clearContext(['userId']); // Remove specific keys
logstyx.clearContext();           // Clear all context

Auto-Instrumentation ​

Automatically capture HTTP requests, responses, errors, and performance metrics without writing manual logging code.

Supported Frameworks ​

  • ✅ Express - Fully supported
  • ✅ Fastify - Fully supported
  • 📜 Koa, Hapi, NestJS - Coming soon

Setup Method 1: Regular Setup ​

Important: Load Order Matters

Require logstyx-js-node BEFORE requiring Express/Fastify. The SDK needs to patch the framework modules before they are loaded.

javascript
// ✅ CORRECT: Logstyx first
const logstyx = require('logstyx-js-node')({
  projectId: 'YOUR_PROJECT_ID',
  apiKey: 'YOUR_API_KEY',
  autoInstrument: true,
  
  // Optional: Configure what to capture
  ignorePaths: ['/health', '/metrics'],
    // Ignore all successful GET requests to reduce noise
  shouldIgnore: (req,res) => req.method === 'GET' && res.statusCode <=400 && !res.isSlow,

  slowRequestThreshold: 1000,
  redactFields: ['password', 'token', 'creditCard'],
  
  // Add custom context to all auto-logged requests
  contextHook: (req) => ({
    tenantId: req.headers['x-tenant-id'],
    orgId: req.user?.organizationId
  })
});

// Then require your framework
const express = require('express');
const app = express();

app.get('/api/users', (req, res) => {
  res.json({ users: [] }); // Auto-logged!
});

app.listen(3000);
javascript
// ❌ WRONG: Framework loaded first won't work
const express = require('express'); // Already cached!
const logstyx = require('logstyx-js-node')({ autoInstrument: true });

Use Node.js --require flag to ensure auto-instrumentation works regardless of require order:

bash
node --require logstyx-js-node/register app.js

package.json:

json
{
  "scripts": {
    "start": "node --require logstyx-js-node/register app.js",
    "dev": "nodemon --require logstyx-js-node/register app.js"
  }
}

app.js (any order now works!):

javascript
const express = require('express');
const app = express();

// Configure logstyx anywhere
const logstyx = require('logstyx-js-node')({
  projectId: 'YOUR_PROJECT_ID',
  apiKey: 'YOUR_API_KEY',
  autoInstrument: true
});

app.get('/api/orders', (req, res) => {
  res.json({ orders: [] }); // Auto-logged!
});

app.listen(3000);

What Gets Logged Automatically? ​

Auto-instrumentation logs requests at different levels based on status and performance:

  • INFO: Successful requests (status 2xx)
  • WARNING: Slow requests (duration > slowRequestThreshold)
  • ERROR: Client errors (status 4xx)
  • CRITICAL: Server errors (status 5xx)

Each log includes:

  • HTTP method, path, URL
  • Status code and response time
  • IP address and user agent
  • Request/response body (with field redaction)
  • Headers (with field redaction)
  • Query parameters and route params
  • User context (if available via req.user, req.session, etc.)
  • Custom context (via contextHook)

Filtering Log Noise

To avoid hitting your log limits with high-traffic but low-value requests (like successful GETs for static data), use the shouldIgnore option:

javascript
const logstyx = require('logstyx-js-node')({
  autoInstrument: true,
  // This will NOT log: GET /api/data (200 OK)
  // This WILL log: GET /api/data (500 Error)
  // This WILL log: POST /api/data (200 OK)
  shouldIgnore: (req,res) => req.method === 'GET' && res.statusCode <=400,
});

Example auto-logged payload:

javascript
{
  title: "GET /api/orders",
  message: "Request completed successfully",
  method: "GET",
  url: "/api/orders",
  path: "/api/orders",
  ip: "192.168.1.1",
  userAgent: "Mozilla/5.0...",
  requestId: "abc-123",
  user: { id: 456, email: "user@example.com" },
  session: { id: "sess_xyz" },
  query: { page: 1 },
  params: {},
  body: { /* request body with redacted fields */ },
  response: { /* response body with redacted fields */ },
  responseTime: 45,
  statusCode: 200,
  isSlow: false,
  // Custom fields from contextHook
  tenantId: "tenant_123",
  environment: "production"
}

Combining Auto + Manual Logging ​

You can use both auto-instrumentation and manual logging together for comprehensive coverage:

javascript
const logstyx = require('logstyx-js-node')({
  projectId: 'YOUR_PROJECT_ID',
  apiKey: 'YOUR_API_KEY',
  autoInstrument: true,
  
  // Add tenant context to all auto-logs
  contextHook: (req) => ({
    tenantId: req.headers['x-tenant-id']
  })
});

const express = require('express');
const app = express();

app.post('/api/orders', async (req, res) => {
  // HTTP request/response is auto-logged with tenantId
  
  // Add custom business logic logs
  logstyx.info({ 
    title: 'Order processing started',
    orderId: req.body.orderId 
  });
  
  try {
    const order = await processOrder(req.body);
    res.json(order); // Auto-logged as INFO
  } catch (error) {
    // Custom error log with additional context
    logstyx.error({
      title: 'Order processing failed',
      orderId: req.body.orderId,
      error: error.message
    });
    throw error; // Also auto-logged as CRITICAL
  }
});

app.listen(3000);

Advanced: Custom Context Hook ​

The contextHook allows you to inject custom data into every auto-logged request:

javascript
const logstyx = require('logstyx-js-node')({
  projectId: 'YOUR_PROJECT_ID',
  apiKey: 'YOUR_API_KEY',
  autoInstrument: true,
  
  contextHook: (req) => {
    return {
      // Multi-tenant support
      tenantId: req.headers['x-tenant-id'],
      orgId: req.user?.organizationId,
      
      // Environment info
      environment: process.env.NODE_ENV,
      version: process.env.APP_VERSION,
      
      // Feature flags
      features: req.user?.enabledFeatures || [],
      
      // Request tracing
      traceId: req.headers['x-trace-id'],
      
      // Custom business context
      subscription: req.user?.subscription?.tier
    };
  }
});

All auto-logged requests will now include these custom fields alongside the standard request information.

Advanced: Custom Payload Builder ​

Override the entire request payload structure:

javascript
const logstyx = require('logstyx-js-node')({
  projectId: 'YOUR_PROJECT_ID',
  apiKey: 'YOUR_API_KEY',
  autoInstrument: true,
  
  buildRequestPayload: (req) => {
    // Custom payload structure
    return {
      // Basic request info
      method: req.method,
      endpoint: req.path,
      
      // Custom user detection
      userId: req.user?.id || req.headers['x-user-id'],
      
      // Custom session handling
      sessionId: req.cookies?.sessionId,
      
      // Include only specific headers
      correlationId: req.headers['x-correlation-id'],
      
      // Business-specific fields
      storeId: req.headers['x-store-id'],
      region: req.headers['x-region']
    };
  }
});

Automatic Device Information ​

The Node.js SDK automatically collects and includes device information with every log:

javascript
{
  type: "node",
  origin: null,
  os: "Linux",           // os.type()
  platform: "linux",     // os.platform()
  browser: null,
  screen: null
}

This information is automatically added to every log payload, helping you identify which server or environment generated the log.

Error Capture ​

Uncaught Exceptions ​

When captureUncaught is enabled, the SDK automatically captures and logs uncaught exceptions:

javascript
const logstyx = require('logstyx-js-node')({
  projectId: 'proj_xyz',
  apiKey: 'key_abc',
  captureUncaught: true
});

// This error will be automatically logged as critical
throw new Error('Unexpected server error');

// Logged as:
// logstyx.critical({
//   title: 'Error',
//   message: 'Unexpected server error',
//   stack: '...'
// });

Process Exit

After logging an uncaught exception, the process will still exit. The SDK logs the error but doesn't prevent the default Node.js behavior.

Unhandled Promise Rejections ​

When captureUnhandledRejections is enabled, unhandled promise rejections are automatically logged:

javascript
const logstyx = require('logstyx-js-node')({
  projectId: 'proj_xyz',
  apiKey: 'key_abc',
  captureUnhandledRejections: true
});

// This rejection will be automatically logged as critical
Promise.reject(new Error('Unhandled async error'));

// Logged as:
// logstyx.critical({
//   title: 'Error',
//   message: 'Unhandled async error',
//   stack: '...'
// });

Manual Error Logging ​

You can still manually log errors with additional context:

javascript
try {
  await riskyOperation();
} catch (error) {
  logstyx.error({
    message: 'Operation failed',
    operation: 'riskyOperation',
    error: error.message,
    stack: error.stack,
    userId: currentUser.id
  });
}

API Methods ​

logstyx.info(data) ​

Log informational messages:

javascript
logstyx.info({ 
  message: 'User authenticated',
  userId: '12345',
  method: 'oauth2'
});

logstyx.warning(data) ​

Log warnings:

javascript
logstyx.warning({ 
  message: 'High memory usage',
  usage: process.memoryUsage().heapUsed,
  threshold: 1024 * 1024 * 500
});

logstyx.error(data) ​

Log errors:

javascript
logstyx.error({ 
  message: 'Database query failed',
  query: 'SELECT * FROM users',
  error: err.message
});

logstyx.critical(data) ​

Log critical issues:

javascript
logstyx.critical({ 
  message: 'Payment processor unavailable',
  service: 'stripe',
  impact: 'All transactions blocked'
});

logstyx.send(level, data) ​

Send a log with a custom level:

javascript
logstyx.send('INFO', { message: 'Custom log' });

logstyx.setContext(context) ​

Set persistent context for all subsequent logs:

javascript
logstyx.setContext({
  environment: process.env.NODE_ENV,
  hostname: require('os').hostname(),
  version: require('./package.json').version
});

logstyx.clearContext(keys?) ​

Clear context:

javascript
// Clear specific keys
logstyx.clearContext(['requestId']);

// Clear all context
logstyx.clearContext();

Complete Examples ​

Express with Auto-Instrumentation ​

javascript
const logstyx = require('logstyx-js-node')({
  projectId: process.env.LOGSTYX_PROJECT_ID,
  apiKey: process.env.LOGSTYX_API_KEY,
  endpoint: 'https://logs.company.com/api/v1/logs',
  autoInstrument: true,
  ignorePaths: ['/health', '/metrics'],
  slowRequestThreshold: 1000,
  redactFields: ['password', 'token', 'creditCard'],
  captureUncaught: true,
  captureUnhandledRejections: true,
  contextHook: (req) => ({
    tenantId: req.headers['x-tenant-id'],
    environment: process.env.NODE_ENV
  })
});

const express = require('express');
const app = express();

app.use(express.json());

// Set application context
logstyx.setContext({
  service: 'api-server',
  version: '1.0.0'
});

// All requests are automatically logged
app.get('/api/users', async (req, res) => {
  try {
    const users = await fetchUsers();
    res.json(users);
  } catch (error) {
    // Additional custom error log
    logstyx.error({
      message: 'Failed to fetch users',
      error: error.message
    });
    res.status(500).json({ error: 'Failed to fetch users' });
  }
});

app.post('/api/orders', async (req, res) => {
  // Business logic logging
  logstyx.info({
    title: 'Order processing started',
    orderId: req.body.orderId
  });
  
  try {
    const order = await processOrder(req.body);
    res.json(order);
  } catch (error) {
    logstyx.error({
      title: 'Order processing failed',
      orderId: req.body.orderId,
      error: error.message
    });
    throw error;
  }
});

app.listen(3000, () => {
  logstyx.info({ 
    message: 'Server started',
    port: 3000
  });
});

Manual Logging Only ​

javascript
const logstyx = require('logstyx-js-node')({
  projectId: process.env.LOGSTYX_PROJECT_ID,
  apiKey: process.env.LOGSTYX_API_KEY,
  endpoint: 'https://logs.company.com/api/v1/logs',
  captureUncaught: true,
  captureUnhandledRejections: true
});

const express = require('express');
const app = express();

// Set application context
logstyx.setContext({
  environment: process.env.NODE_ENV,
  service: 'api-server',
  version: '1.0.0'
});

// Manual request logging middleware
app.use((req, res, next) => {
  const start = Date.now();
  
  res.on('finish', () => {
    logstyx.info({
      message: 'HTTP request',
      method: req.method,
      path: req.path,
      statusCode: res.statusCode,
      duration: Date.now() - start
    });
  });
  
  next();
});

// Error handling middleware
app.use((err, req, res, next) => {
  logstyx.error({
    message: 'Request error',
    error: err.message,
    stack: err.stack,
    method: req.method,
    path: req.path
  });
  
  res.status(500).json({ error: 'Internal server error' });
});

app.listen(3000, () => {
  logstyx.info({ 
    message: 'Server started',
    port: 3000
  });
});

Best Practices ​

Use Environment Variables ​

Store credentials in environment variables:

javascript
// .env file
LOGSTYX_PROJECT_ID=proj_abc123
LOGSTYX_API_KEY=key_xyz789
LOGSTYX_ENDPOINT=https://logs.company.com/api/v1/logs
NODE_ENV=production

// app.js
require('dotenv').config();

const logstyx = require('logstyx-js-node')({
  projectId: process.env.LOGSTYX_PROJECT_ID,
  apiKey: process.env.LOGSTYX_API_KEY,
  endpoint: process.env.LOGSTYX_ENDPOINT
});

Enable Auto-Instrumentation in Production ​

Use auto-instrumentation to capture all HTTP traffic automatically:

javascript
const logstyx = require('logstyx-js-node')({
  projectId: process.env.LOGSTYX_PROJECT_ID,
  apiKey: process.env.LOGSTYX_API_KEY,
  autoInstrument: process.env.NODE_ENV === 'production',
  captureUncaught: process.env.NODE_ENV === 'production',
  captureUnhandledRejections: process.env.NODE_ENV === 'production'
});

Set Application Context ​

Provide context that helps identify logs:

javascript
logstyx.setContext({
  environment: process.env.NODE_ENV,
  hostname: require('os').hostname(),
  service: 'payment-api',
  version: require('./package.json').version,
  region: process.env.AWS_REGION
});

Structure Your Logs ​

Use consistent structure for better searchability:

javascript
// ❌ Avoid
logstyx.info('User john@example.com logged in');

// ✅ Better
logstyx.info({
  message: 'User logged in',
  email: 'john@example.com',
  timestamp: Date.now()
});

Log Performance Metrics ​

Track performance of operations:

javascript
async function processPayment(order) {
  const start = Date.now();
  
  try {
    const result = await stripe.charge(order);
    
    logstyx.info({
      message: 'Payment processed',
      orderId: order.id,
      amount: order.amount,
      duration: Date.now() - start,
      success: true
    });
    
    return result;
  } catch (error) {
    logstyx.error({
      message: 'Payment failed',
      orderId: order.id,
      amount: order.amount,
      duration: Date.now() - start,
      error: error.message
    });
    
    throw error;
  }
}

Avoid Logging Sensitive Data ​

Never log passwords, tokens, or PII. Use the redactFields option:

javascript
const logstyx = require('logstyx-js-node')({
  projectId: 'YOUR_PROJECT_ID',
  apiKey: 'YOUR_API_KEY',
  autoInstrument: true,
  redactFields: [
    'password',
    'token',
    'authorization',
    'secret',
    'apiKey',
    'creditCard',
    'ssn',
    'socialSecurity'
  ]
});
javascript
// ❌ Dangerous
logstyx.info({ 
  user: {
    email: user.email,
    password: user.password, // Never log passwords!
    creditCard: user.card // Never log credit cards!
  }
});

// ✅ Safe
logstyx.info({
  message: 'User updated',
  userId: user.id,
  email: user.email,
  action: 'profile_update'
});

Use Appropriate Log Levels ​

Choose the right level for each log:

  • info: Normal operations, state changes, important events
  • warning: Potential issues, deprecated features, high resource usage
  • error: Failures that were handled, retryable errors
  • critical: System failures, unhandled errors, service outages
javascript
// Info: Normal operation
logstyx.info({ message: 'Cache refreshed', entries: 1000 });

// Warning: Concerning but not broken
logstyx.warning({ 
  message: 'Response time high',
  duration: 2000,
  threshold: 1000 
});

// Error: Something failed but was handled
logstyx.error({ 
  message: 'Email delivery failed',
  recipient: 'user@example.com',
  retry: true 
});

// Critical: System-level failure
logstyx.critical({ 
  message: 'Database connection lost',
  database: 'production-db',
  impact: 'All writes blocked' 
});

Troubleshooting ​

Auto-instrumentation not working? ​

Check load order:

  • Make sure logstyx-js-node is required BEFORE Express/Fastify
  • Or use --require logstyx-js-node/register flag
bash
node --require logstyx-js-node/register app.js

Logs not appearing? ​

  1. Verify projectId and apiKey are correct
  2. Check network connectivity to the endpoint
  3. Look for console errors
  4. Ensure the path isn't in ignorePaths

Too many logs? ​

  1. Add paths to ignore:
javascript
ignorePaths: ['/health', '/metrics', '/favicon.ico', '/static/*']
  1. Filter by Method/Status: Use the shouldIgnore hook to silence successful GET requests while maintaining visibility on errors
javascript
// Silence successful & fast GETs only
    shouldIgnore: (req,res) => req.method === 'GET' && res.statusCode <=400 && !res.isSlow,

Sensitive data in logs? ​

Add fields to redact:

javascript
redactFields: ['password', 'ssn', 'creditCard', 'apiKey', 'token']

Released under the MIT License.