// ═══════════════════════════════════════════════════════════ // 📱 Example Express App with OpenTelemetry // ═══════════════════════════════════════════════════════════ // // Run with: npm run trace // Or: node --require ./tracing.js app.js const express = require('express'); const { trace, SpanStatusCode } = require('@opentelemetry/api'); const app = express(); const PORT = process.env.PORT || 3000; // Get a tracer for manual instrumentation const tracer = trace.getTracer('example-app'); // Simulated database const users = [ { id: 1, name: 'Alice', email: 'alice@example.com' }, { id: 2, name: 'Bob', email: 'bob@example.com' }, { id: 3, name: 'Charlie', email: 'charlie@example.com' }, ]; // Middleware to add request tracing app.use((req, res, next) => { const span = trace.getActiveSpan(); if (span) { span.setAttribute('http.user_agent', req.get('user-agent') || 'unknown'); } next(); }); // Health check app.get('/health', (req, res) => { res.json({ status: 'healthy', service: 'nodejs-example' }); }); // Get all users (with manual span) app.get('/users', async (req, res) => { // Create a custom span for database operation const span = tracer.startSpan('db.query.users'); span.setAttribute('db.system', 'memory'); span.setAttribute('db.operation', 'SELECT'); try { // Simulate database latency await sleep(Math.random() * 100); span.setAttribute('db.row_count', users.length); span.setStatus({ code: SpanStatusCode.OK }); res.json({ users }); } catch (error) { span.setStatus({ code: SpanStatusCode.ERROR, message: error.message, }); span.recordException(error); res.status(500).json({ error: error.message }); } finally { span.end(); } }); // Get user by ID app.get('/users/:id', async (req, res) => { const userId = parseInt(req.params.id); const span = tracer.startSpan('db.query.user_by_id'); span.setAttribute('db.system', 'memory'); span.setAttribute('db.operation', 'SELECT'); span.setAttribute('user.id', userId); try { await sleep(Math.random() * 50); const user = users.find(u => u.id === userId); if (!user) { span.setStatus({ code: SpanStatusCode.ERROR, message: 'User not found' }); res.status(404).json({ error: 'User not found' }); } else { span.setStatus({ code: SpanStatusCode.OK }); res.json({ user }); } } finally { span.end(); } }); // Create order (simulates complex operation with nested spans) app.post('/orders', express.json(), async (req, res) => { const parentSpan = tracer.startSpan('order.create'); try { // Step 1: Validate inventory const inventorySpan = tracer.startSpan('inventory.check', { attributes: { 'order.items': req.body.items?.length || 0 }, }); await sleep(Math.random() * 100); inventorySpan.setStatus({ code: SpanStatusCode.OK }); inventorySpan.end(); // Step 2: Process payment const paymentSpan = tracer.startSpan('payment.process', { attributes: { 'payment.method': 'credit_card' }, }); await sleep(Math.random() * 200); paymentSpan.setStatus({ code: SpanStatusCode.OK }); paymentSpan.end(); // Step 3: Create order record const createSpan = tracer.startSpan('db.insert.order'); await sleep(Math.random() * 50); const orderId = Date.now().toString(36); createSpan.setAttribute('order.id', orderId); createSpan.setStatus({ code: SpanStatusCode.OK }); createSpan.end(); parentSpan.setStatus({ code: SpanStatusCode.OK }); res.json({ orderId, status: 'created' }); } catch (error) { parentSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.message }); parentSpan.recordException(error); res.status(500).json({ error: error.message }); } finally { parentSpan.end(); } }); // Simulate error endpoint (for testing error traces) app.get('/error', (req, res) => { const span = trace.getActiveSpan(); const error = new Error('Simulated error for testing'); if (span) { span.recordException(error); span.setStatus({ code: SpanStatusCode.ERROR, message: error.message }); } res.status(500).json({ error: error.message }); }); // Helper function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // Start server app.listen(PORT, () => { console.log(`🚀 Example app listening on http://localhost:${PORT}`); console.log(''); console.log('Try these endpoints:'); console.log(` GET http://localhost:${PORT}/health`); console.log(` GET http://localhost:${PORT}/users`); console.log(` GET http://localhost:${PORT}/users/1`); console.log(` POST http://localhost:${PORT}/orders`); console.log(` GET http://localhost:${PORT}/error`); });