Skip to content

Security Logging: Auditing and Monitoring for Security Events

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Security Logging: Auditing and Monitoring for Security Events. We cover key concepts, practical examples, and best practices to help you master this topic.

Security logging records events relevant to the security of your application: authentication attempts, authorization failures, input validation errors, rate limit triggers, and suspicious activity patterns. These logs feed into monitoring systems that detect and respond to security incidents.

flowchart TB
    subgraph Events
        Login[Login Success/Failure]
        AuthZ[Authorization Denied]
        Rate[Rate Limit Triggered]
        Input[Validation Error]
        Admin[Admin Action]
        API[API Key Usage]
    end
    
    Events --> Logger[Security Logger]
    Logger -->|Structured JSON| LogAggregator[Log Aggregator]
    LogAggregator --> Storage[(Elasticsearch / Loki)]
    Storage --> Detection[Detection Rules]
    Detection -->|Alert| SIEM[SIEM / AlertManager]
    Detection -->|Dashboard| Grafana
    SIEM --> Response[Incident Response]

What You'll Learn

  • Security event types and what to log
  • Structured logging with correlation IDs
  • Log integrity and tamper prevention
  • Detection rules for common attack patterns

Why It Matters

Without security logging, you cannot detect breaches in progress, investigate incidents after the fact, or meet Compliance requirements (SOC2, PCI-DSS, HIPAA). Security logs are often the only record of an attacker's actions.

Real-World Use

A SaaS platform logs every authentication event with user ID, IP, user agent, and result. Anomaly detection identifies when a user logs in from a new country within 5 minutes of a previous login from another country. This pattern detected a credential stuffing attack affecting 50 accounts.

Security Logging Implementation

Structured Security Logger

const { createLogger, format, transports } = require('winston');

const securityLogger = createLogger({
  level: 'info',
  format: format.combine(
    format.timestamp(),
    format.json()
  ),
  defaultMeta: { service: 'api', type: 'security' },
  transports: [
    new transports.File({ filename: 'logs/security.log', maxSize: '100m' }),
    new transports.Console({ format: format.json() })
  ]
});

function logSecurityEvent(eventType, details, severity = 'info') {
  securityLogger.log(severity, eventType, {
    eventType,
    timestamp: new Date().toISOString(),
    correlationId: details.correlationId,
    userId: details.userId,
    ip: details.ip,
    userAgent: details.userAgent,
    resource: details.resource,
    action: details.action,
    result: details.result,
    reason: details.reason,
    metadata: details.metadata
  });
}

// Usage
app.post('/api/login', async (req, res) => {
  const authResult = await authenticate(req.body);

  logSecurityEvent('LOGIN_ATTEMPT', {
    correlationId: req.correlationId,
    userId: req.body.username,
    ip: req.ip,
    userAgent: req.headers['user-agent'],
    action: 'login',
    result: authResult.success ? 'success' : 'failure',
    reason: authResult.success ? null : 'invalid_password'
  });

  if (!authResult.success) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }

  // Proceed with login
});

Expected output:

{"level":"info","eventType":"LOGIN_ATTEMPT","userId":"john","result":"failure","timestamp":"2026-06-28T10:30:00Z","correlationId":"abc-123"}

Security Detection Rules

class SecurityDetector {
  constructor() {
    this.events = [];
  }

  addEvent(event) {
    this.events.push(event);
    this.runDetectionRules(event);
  }

  runDetectionRules(event) {
    // Brute force detection: 5+ failed logins in 60 seconds
    if (event.eventType === 'LOGIN_ATTEMPT' && event.result === 'failure') {
      const recentFailures = this.events.filter(e =>
        e.eventType === 'LOGIN_ATTEMPT' &&
        e.result === 'failure' &&
        (e.userId === event.userId || e.ip === event.ip) &&
        Date.now() - new Date(e.timestamp).getTime() < 60000
      );

      if (recentFailures.length >= 5) {
        this.triggerAlert('BRUTE_FORCE_DETECTED', {
          target: event.userId,
          ip: event.ip,
          attempts: recentFailures.length,
          window: '60s'
        });
      }
    }

    // Impossible travel: same user from different countries within 5 minutes
    if (event.eventType === 'LOGIN_ATTEMPT' && event.result === 'success') {
      const previous = this.events.filter(e =>
        e.eventType === 'LOGIN_ATTEMPT' &&
        e.result === 'success' &&
        e.userId === event.userId &&
        Date.now() - new Date(e.timestamp).getTime() < 300000
      );

      if (previous.length > 0 && previous[previous.length - 1].ip !== event.ip) {
        this.triggerAlert('IMPOSSIBLE_TRAVEL', {
          userId: event.userId,
          previousIp: previous[previous.length - 1].ip,
          newIp: event.ip,
          timeDiff: Date.now() - new Date(previous[previous.length - 1].timestamp).getTime()
        });
      }
    }
  }

  triggerAlert(alertType, details) {
    console.error(`SECURITY ALERT: ${alertType}`, JSON.stringify(details));
    // Send to SIEM / PagerDuty / Slack
  }
}

Expected output:

SECURITY ALERT: BRUTE_FORCE_DETECTED {"target":"john","ip":"192.168.1.100","attempts":5}
SECURITY ALERT: IMPOSSIBLE_TRAVEL {"userId":"jane","previousIp":"US IP","newIp":"CN IP"}

Audit Trail Middleware

function auditTrail(action) {
  return async (req, res, next) => {
    const originalSend = res.json.bind(res);
    const startTime = Date.now();

    res.json = function(body) {
      logSecurityEvent('AUDIT_' + action.toUpperCase(), {
        correlationId: req.correlationId,
        userId: req.user?.sub,
        ip: req.ip,
        action,
        resource: req.originalUrl,
        method: req.method,
        statusCode: res.statusCode,
        responseTime: Date.now() - startTime,
        changes: body
      });

      return originalSend(body);
    };

    next();
  };
}

// Usage
app.post('/api/users', auditTrail('create_user'), async (req, res) => {
  const user = await createUser(req.body);
  res.status(201).json(user);
});

Expected output:

On user creation, audit log entry includes who created the user, when, from which IP, and the created user data.

Common Mistakes

  • Logging sensitive data (passwords, tokens, PII) in plaintext — mask or exclude sensitive fields.
  • Not including correlation IDs — without correlation, you cannot trace a request across services.
  • Using unstructured (plain text) logs instead of structured (JSON) logs — structured logs are searchable and parseable.
  • Not monitoring logs in real-time — logs stored but never reviewed provide no security value.
  • Allowing log tampering — logs should be append-only and shipped to a separate, immutable storage.

Practice Questions

  1. What security events should be logged?
  2. Why is structured logging important for security?
  3. What is a correlation ID and why is it useful?
  4. How do you detect a brute force attack from logs?
  5. What is the difference between logging and monitoring?

Challenge

Design a security logging system for a banking API. Define 10 security event types. Implement detection rules for: brute force login, impossible travel, unusual API key usage, and admin action auditing. Ship logs to a central location and create a Grafana dashboard.

FAQ

What is the difference between logging and monitoring?

Logging records events. Monitoring analyzes logs for patterns and alerts on anomalies. Both are needed: logs provide evidence; monitoring provides real-time detection.

What security events should I log?

Authentication (success/failure), authorization failures, input validation errors, rate limit triggers, admin actions, API key usage, data access/modification, and configuration changes.

How long should I retain security logs?

Compliance requirements vary: PCI-DSS requires 1 year, SOC2 requires 6 months, GDPR requires proof of processing. Retain at least 90 days for incident response, archive for 1-7 years.

Should I log passwords or tokens?

Never log passwords, tokens, or secrets. Mask them with [FILTERED]. Log only that an authentication event occurred and whether it succeeded.

What is a SIEM system?

Security Information and Event Management (SIEM) aggregates logs from multiple sources, correlates events, and generates alerts. Examples: Splunk, ELK Stack, Wazuh.

Mini Project

Build a security logging module for your API. Log all authentication attempts, authorization failures, and admin actions. Implement detection rules for brute force and impossible travel. Ship logs to a local ELK Stack. Create a dashboard showing login failure rates and top blocked IPs.

What's Next

Continue to DDoS Protection to learn about protecting your backend from distributed denial-of-service attacks.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro