/

Error Logging

ByteHide Logger provides specialized methods for handling errors: error and critical. Both methods can accept an Error parameter to automatically capture exception details like stack traces and error types.

Error Logging Methods

Error Method

Use error for exceptions that affect functionality but allow the application to continue:

// Method signature
Log.error(message, options, error)

// Basic error logging
try {
    await processOrder(orderId);
} catch (error) {
    Log.error('Failed to process order', {}, error);
}

// Error with context
try {
    await processPayment(paymentRequest);
} catch (error) {
    Log.error('Payment processing failed', {
        context: { 
            transactionId: paymentRequest.transactionId,
            amount: paymentRequest.amount 
        },
        tags: ['payment', 'error']
    }, error);
}

Critical Method

Use critical for critical errors that may cause application termination:

// Method signature  
Log.critical(message, options, error)

// Critical system failures
try {
    await initializeDatabase();
} catch (error) {
    Log.critical('Database initialization failed - application cannot continue', {
        context: { connectionString: '***' }
    }, error);
    process.exit(1);
}

// Critical configuration errors
try {
    await loadConfiguration();
} catch (error) {
    Log.critical('Invalid configuration detected - shutting down', {
        tags: ['config', 'critical']
    }, error);
    throw error;
}

Error Information Captured

When you pass an Error to error or critical methods, ByteHide Logger automatically captures:

  • Error Name: The error's name/type
  • Error Message: The error's message
  • Stack Trace: Complete stack trace for debugging
  • Error Properties: Additional properties attached to the error
try {
    const result = await callExternalApi();
} catch (error) {
    // All error details are automatically captured
    Log.error('External API call failed', {
        context: { endpoint: '/api/payments' }
    }, error);
    
    // Logged information includes:
    // - Error name: TypeError, ReferenceError, etc.
    // - Message: "Network request failed"
    // - Stack trace: Full call stack
    // - Additional error properties
}

Common Error Scenarios

API Calls

try {
    const response = await fetch('/api/orders', {
        method: 'POST',
        body: JSON.stringify(orderData)
    });
    
    if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }
    
    return await response.json();
} catch (error) {
    Log.error('API request failed', {
        context: { 
            endpoint: '/api/orders',
            method: 'POST',
            status: error.status 
        },
        tags: ['api', 'error']
    }, error);
    throw error;
}

Database Operations

try {
    const orders = await database.query('SELECT * FROM orders WHERE customer_id = ?', [customerId]);
    return orders;
} catch (error) {
    Log.error('Database query failed', {
        context: { 
            customerId,
            query: 'getOrdersByCustomer' 
        },
        metadata: { timeout: 30000 },
        tags: ['database', 'error']
    }, error);
    throw error;
}

File Operations

try {
    const content = await fs.readFile(filePath, 'utf8');
    return JSON.parse(content);
} catch (error) {
    if (error.code === 'ENOENT') {
        Log.error('Configuration file not found', {
            context: { filePath },
            tags: ['config', 'file']
        }, error);
    } else if (error instanceof SyntaxError) {
        Log.critical('Invalid JSON configuration', {
            context: { filePath },
            tags: ['config', 'json', 'critical']
        }, error);
    } else {
        Log.error('File operation failed', {
            context: { filePath, operation: 'read' }
        }, error);
    }
    throw error;
}

Business Logic Errors

class OrderService {
    async validateAndProcessOrder(order) {
        try {
            await this.validateOrder(order);
            return await this.processOrder(order);
        } catch (error) {
            if (error instanceof ValidationError) {
                Log.error('Order validation failed', {
                    context: { 
                        orderId: order.id,
                        validationErrors: error.errors 
                    },
                    tags: ['validation', 'orders']
                }, error);
            } else if (error instanceof InsufficientStockError) {
                Log.error('Insufficient stock for order', {
                    context: { 
                        orderId: order.id,
                        productId: error.productId,
                        requestedQuantity: error.requestedQuantity,
                        availableStock: error.availableStock 
                    },
                    tags: ['inventory', 'orders']
                }, error);
            } else {
                Log.critical('Unexpected error in order processing', {
                    context: { orderId: order.id },
                    tags: ['orders', 'critical']
                }, error);
            }
            throw error;
        }
    }
}

Error Handling Patterns

Catch and Log

async function getOrder(orderId) {
    try {
        return await orderRepository.findById(orderId);
    } catch (error) {
        Log.error('Failed to retrieve order', {
            context: { orderId },
            tags: ['repository', 'orders']
        }, error);
        throw error; // Re-throw to preserve original error
    }
}

Catch, Log, and Transform

async function getOrderSafely(orderId) {
    try {
        const order = await orderRepository.findById(orderId);
        return { success: true, data: order };
    } catch (error) {
        if (error.name === 'NotFoundError') {
            Log.error('Order not found', {
                context: { orderId }
            }, error);
            return { success: false, error: 'Order not found' };
        } else {
            Log.critical('Unexpected error retrieving order', {
                context: { orderId }
            }, error);
            return { success: false, error: 'Internal server error' };
        }
    }
}

Critical Failure Handling

async function startApplication() {
    try {
        await initializeDatabase();
        await loadConfiguration();
        await startServices();
    } catch (error) {
        if (error.name === 'DatabaseConnectionError') {
            Log.critical('Database initialization failed', {
                tags: ['startup', 'database']
            }, error);
            process.exit(1);
        } else if (error.name === 'ConfigurationError') {
            Log.critical('Configuration loading failed', {
                tags: ['startup', 'config']
            }, error);
            process.exit(1);
        } else {
            Log.critical('Application startup failed', {
                tags: ['startup', 'critical']
            }, error);
            process.exit(1);
        }
    }
}

Express.js Integration

Route Error Handling

app.get('/api/orders/:id', async (req, res) => {
    try {
        const order = await orderService.getOrder(req.params.id);
        res.json(order);
    } catch (error) {
        if (error.name === 'NotFoundError') {
            Log.error('Order not found', {
                context: { 
                    orderId: req.params.id,
                    requestId: req.id 
                },
                tags: ['api', 'orders']
            }, error);
            res.status(404).json({ error: 'Order not found' });
        } else {
            Log.critical('Unexpected error in getOrder endpoint', {
                context: { 
                    orderId: req.params.id,
                    requestId: req.id 
                },
                tags: ['api', 'orders', 'critical']
            }, error);
            res.status(500).json({ error: 'Internal server error' });
        }
    }
});

Global Error Handler

app.use((error, req, res, next) => {
    const requestInfo = {
        requestId: req.id,
        path: req.path,
        method: req.method,
        query: req.query
    };

    if (error.status && error.status < 500) {
        Log.error('Client error', {
            context: requestInfo,
            metadata: { statusCode: error.status },
            tags: ['http', 'client-error']
        }, error);
        res.status(error.status);
    } else {
        Log.critical('Server error', {
            context: requestInfo,
            tags: ['http', 'server-error']
        }, error);
        res.status(500);
    }

    res.json({ error: 'An error occurred' });
});

Best Practices

Error Logging Best Practices

  • Always pass the Error: Include the Error parameter to capture full details
  • Add relevant context: Include business context like IDs, operation names, and state
  • Use appropriate levels: error for recoverable issues, critical for system failures
  • Don't swallow errors: Log and re-throw or transform appropriately
  • Include correlation IDs: Use correlation IDs for request tracking
  • Avoid sensitive data: Don't log passwords, tokens, or PII in error context

Common Mistakes to Avoid

// ❌ Don't lose error details
try {
    await processOrder(order);
} catch (error) {
    Log.error('Something went wrong'); // Missing error parameter
    throw new Error('Operation failed'); // Lost original error
}

// ✅ Capture full error details
try {
    await processOrder(order);
} catch (error) {
    Log.error('Order processing failed', {
        context: { orderId: order.id }
    }, error);
    throw error; // Preserve original error
}

// ❌ Don't log and swallow
try {
    await processOrder(order);
} catch (error) {
    Log.error('Error occurred', {}, error);
    return null; // Swallowing error
}

// ✅ Log and handle appropriately
try {
    await processOrder(order);
} catch (error) {
    Log.error('Error occurred', {}, error);
    throw error; // Or return appropriate error response
}

Next Steps

Previous
Tags