/

User Identification

User identification allows you to associate logs with specific users, making it easier to track user actions, debug user-specific issues, and maintain audit trails.

Basic Usage

Use Log.identify() to associate logs with a specific user:

// Identify user with id, email, and token
Log.identify('user_12345', 'john.doe@company.com', 'auth_token_abc123');

// All subsequent logs will be associated with this user
Log.info('User performed action');
Log.error('User encountered error', {
    context: { action: 'checkout' }
});

// Logout to make subsequent logs anonymous
Log.logout();

Method Signature

Log.identify(id, email?, token?)

Parameters

  • id (string, required): Unique user identifier
  • email (string, optional): User's email address
  • token (string, optional): Authentication token

User Identification Examples

Basic Identification

// Minimal identification with just ID
Log.identify('user_12345');

// With email
Log.identify('user_12345', 'john.doe@company.com');

// Complete identification
Log.identify('user_12345', 'john.doe@company.com', 'jwt_token_here');

Express.js Integration

// Login endpoint
app.post('/api/login', async (req, res) => {
    try {
        const { email, password } = req.body;
        const user = await authService.authenticate(email, password);
        
        // Identify user in logs
        Log.identify(user.id, user.email, user.token);
        
        Log.info('User login successful', {
            context: { userId: user.id, loginMethod: 'email' },
            tags: ['authentication', 'login']
        });
        
        res.json({ token: user.token });
    } catch (error) {
        Log.error('Login failed', {
            context: { email: req.body.email },
            tags: ['authentication', 'error']
        }, error);
        
        res.status(401).json({ error: 'Invalid credentials' });
    }
});

// Logout endpoint
app.post('/api/logout', (req, res) => {
    Log.info('User logout', {
        tags: ['authentication', 'logout']
    });
    
    Log.logout();
    res.json({ message: 'Logged out successfully' });
});

Middleware Integration

// Authentication middleware
const authMiddleware = async (req, res, next) => {
    try {
        const token = req.headers.authorization?.replace('Bearer ', '');
        
        if (!token) {
            return res.status(401).json({ error: 'No token provided' });
        }
        
        const user = await authService.verifyToken(token);
        
        // Identify user for all subsequent logs in this request
        Log.identify(user.id, user.email, token);
        
        req.user = user;
        next();
    } catch (error) {
        Log.error('Authentication failed', {
            context: { token: token?.substring(0, 10) + '...' },
            tags: ['authentication', 'middleware']
        }, error);
        
        res.status(401).json({ error: 'Invalid token' });
    }
};

// Protected route
app.get('/api/profile', authMiddleware, (req, res) => {
    Log.info('Profile accessed', {
        context: { userId: req.user.id },
        tags: ['profile', 'access']
    });
    
    res.json(req.user);
});

User Context in Logs

Once a user is identified, all subsequent logs will include user information:

// After identification
Log.identify('user_123', 'john@example.com');

// These logs will automatically include user context
Log.info('Order created', {
    context: { orderId: 'order_456' },
    tags: ['orders']
});

Log.error('Payment failed', {
    context: { paymentId: 'pay_789' },
    tags: ['payment', 'error']
});

Logout Functionality

Use Log.logout() to make subsequent logs anonymous:

// User logs out
Log.logout();

// Subsequent logs will be anonymous
Log.info('Anonymous action performed');

Session Management

Session-based Identification

// Express session example
app.use(session({
    secret: 'your-secret-key',
    resave: false,
    saveUninitialized: false
}));

app.post('/api/login', async (req, res) => {
    const user = await authService.authenticate(req.body.email, req.body.password);
    
    // Store in session
    req.session.userId = user.id;
    req.session.userEmail = user.email;
    
    // Identify in logs
    Log.identify(user.id, user.email);
    
    Log.info('User session created', {
        context: { sessionId: req.session.id },
        tags: ['session', 'login']
    });
    
    res.json({ success: true });
});

// Middleware to restore user identification from session
app.use((req, res, next) => {
    if (req.session.userId) {
        Log.identify(req.session.userId, req.session.userEmail);
    }
    next();
});

JWT Token Integration

import jwt from 'jsonwebtoken';

// JWT middleware
const jwtMiddleware = (req, res, next) => {
    const token = req.headers.authorization?.replace('Bearer ', '');
    
    if (token) {
        try {
            const decoded = jwt.verify(token, process.env.JWT_SECRET);
            
            // Identify user from JWT payload
            Log.identify(decoded.userId, decoded.email, token);
            
            req.user = decoded;
        } catch (error) {
            Log.error('JWT verification failed', {
                context: { tokenPrefix: token.substring(0, 10) },
                tags: ['jwt', 'authentication']
            }, error);
        }
    }
    
    next();
};

Best Practices

User Identification Best Practices

  • Set user context early: Configure user identification as soon as user is authenticated
  • Include relevant information: Add email and token when available
  • Clear on logout: Always call Log.logout() when user logs out
  • Use consistent user IDs: Maintain the same user ID format across your application
  • Consider privacy: Be mindful of PII in user identification data

Common Patterns

Single Page Applications

// React/Vue.js example
class AuthService {
    async login(email, password) {
        try {
            const response = await fetch('/api/login', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ email, password })
            });
            
            const data = await response.json();
            
            if (data.success) {
                // Store token and identify user
                localStorage.setItem('token', data.token);
                Log.identify(data.user.id, data.user.email, data.token);
                
                Log.info('User authenticated', {
                    context: { loginType: 'spa' },
                    tags: ['authentication', 'spa']
                });
            }
            
            return data;
        } catch (error) {
            Log.error('Login request failed', {
                context: { email },
                tags: ['authentication', 'spa', 'error']
            }, error);
            throw error;
        }
    }
    
    logout() {
        localStorage.removeItem('token');
        Log.logout();
        
        Log.info('User logged out', {
            tags: ['authentication', 'logout', 'spa']
        });
    }
    
    // Restore user identification on app start
    restoreSession() {
        const token = localStorage.getItem('token');
        if (token) {
            try {
                const payload = jwt.decode(token);
                if (payload && payload.exp > Date.now() / 1000) {
                    Log.identify(payload.userId, payload.email, token);
                    
                    Log.info('Session restored', {
                        context: { userId: payload.userId },
                        tags: ['authentication', 'session']
                    });
                }
            } catch (error) {
                Log.error('Session restoration failed', {}, error);
                this.logout();
            }
        }
    }
}

Microservices Communication

// Service-to-service calls with user context
class ApiClient {
    constructor() {
        this.baseURL = process.env.API_BASE_URL;
    }
    
    async makeRequest(endpoint, options = {}) {
        // Get current user context if available
        const userContext = this.getCurrentUserContext();
        
        const headers = {
            'Content-Type': 'application/json',
            ...options.headers
        };
        
        // Pass user context in headers for service-to-service calls
        if (userContext) {
            headers['X-User-ID'] = userContext.id;
            headers['X-User-Email'] = userContext.email;
        }
        
        try {
            const response = await fetch(`${this.baseURL}${endpoint}`, {
                ...options,
                headers
            });
            
            Log.info('API request completed', {
                context: { 
                    endpoint, 
                    status: response.status,
                    userId: userContext?.id 
                },
                tags: ['api', 'microservice']
            });
            
            return response;
        } catch (error) {
            Log.error('API request failed', {
                context: { endpoint, userId: userContext?.id },
                tags: ['api', 'microservice', 'error']
            }, error);
            throw error;
        }
    }
}

Next Steps

Previous
Data Masking