Skip to content

Application logging for software developers

Application logging is your first line of defense in cybersecurity monitoring and incident response. When implemented correctly, logs become powerful allies for security teams, enabling rapid threat detection, forensic analysis, and compliance reporting. However, poorly structured logs can become noise that obscures critical security events and hampers investigation efforts.

This guide explores key principles for implementing logging that seamlessly integrates with modern log management platforms while providing maximum value for cybersecurity operations.

The Foundation: Structure Over Chaos

Principle 1: Embrace Structured Logging

Unstructured log messages like "User john_doe logged in from 192.168.1.100 at 2025-06-28 14:30:22" may be human-readable, but they're nightmares for automated analysis. Structured logging using JSON format enables powerful querying, alerting, and correlation.

Example of the structured log

{
    "@timestamp": "2025-06-28T14:30:22.000Z",
    "event": {
        "category": ["authentication"],
        "type": ["start"],
        "outcome": "success"
    },
    "user": {
        "name": "john_doe",
        "id": "12345"
    },
    "source": {
        "ip": "192.168.1.100"
    },
    "message": "User authentication successful"
}

Principle 2: Leverage Elastic Common Schema (ECS)

ECS provides a standardized field mapping that ensures consistency across different applications and data sources. This standardization is crucial for security operations where analysts need to correlate events from multiple systems quickly.

Key ECS fields for security logging include:

  • @timestamp: Event timestamp in ISO 8601 format
  • event.category: High-level categorization (authentication, network, process, etc.)
  • event.type: Specific event type (start, end, creation, deletion, etc.)
  • event.outcome: Success, failure, or unknown
  • user.*: User identification and details
  • source.* and destination.*: Network connection details
  • process.*: Process execution information
  • file.*: File operation details

Tip

Always use UTC, the local timezones are non-deterministic and much more prone to errors.

Tip

Prefer UTF-8 as a charset for your log messages.

Security-Critical Logging Categories

Authentication and Authorization Events

These events are goldmines for detecting credential stuffing, brute force attacks, and privilege escalation attempts.

Example of log that describes a failed login

{
    "@timestamp": "2025-06-28T15:45:33.000Z",
    "event": {
        "category": ["authentication"],
        "type": ["start"],
        "outcome": "failure"
    },
    "user": {
        "name": "admin",
        "target": {
            "name": "privileged_service"
        }
    },
    "source": {
        "ip": "203.0.113.42",
        "geo": {
            "country_name": "Unknown"
        }
    },
    "error": {
        "message": "Invalid credentials provided"
    },
    "labels": {
        "risk_score": "high"
    }
}

Network Activity Logs

Critical for detecting lateral movement, data ex-filtration, and command-and-control communications.

Example of network activity log

{
    "@timestamp": "2025-06-28T16:20:15.000Z",
    "event": {
        "category": ["network"],
        "type": ["connection"],
        "outcome": "success"
    },
    "source": {
        "ip": "10.0.1.50",
        "port": 4433
    },
    "destination": {
        "ip": "198.51.100.25",
        "port": 443,
        "domain": "suspicious-domain.example"
    },
    "network": {
        "protocol": "tcp",
        "bytes": 1048576
    },
    "url": {
        "full": "https://suspicious-domain.example/data/export"
    }
}

File and Process Operations

Essential for malware detection, insider threat monitoring, and compliance.

Example of log about process launch

{
    "@timestamp": "2025-06-28T17:10:44.000Z",
    "event": {
        "category": ["process"],
        "type": ["start"],
        "outcome": "success"
    },
    "process": {
        "name": "powershell.exe",
        "pid": 2847,
        "command_line": "powershell.exe -ExecutionPolicy Bypass -File C:\\temp\\script.ps1",
        "parent": {
            "name": "cmd.exe",
            "pid": 1924
        }
    },
    "user": {
        "name": "employee_user",
        "domain": "corporate"
    },
    "host": {
        "name": "workstation-042",
        "os": {
            "name": "Windows",
            "version": "10"
        }
    }
}

Implementation Best Practices

Context Enrichment

Raw events gain security value through contextual enrichment. Include relevant metadata that helps security analysts understand the significance of events.

Example in Python
import logging
import json
from datetime import datetime, timezone

class SecurityLogger:
    def __init__(self, service_name):
        self.service_name = service_name
        self.logger = logging.getLogger(service_name)

    def log_authentication_event(self, user_id, source_ip, outcome, session_id=None, user_agent=None):
        event = {
            "@timestamp": datetime.now(timezone.utc).isoformat(),
            "event": {
                "category": ["authentication"],
                "type": ["start"],
                "outcome": outcome
            },
            "service": {
                "name": self.service_name
            },
            "user": {
                "id": user_id
            },
            "source": {
                "ip": source_ip
            }
        }

        # Add contextual information
        if session_id:
            event["session"] = {"id": session_id}
        if user_agent:
            event["user_agent"] = {"original": user_agent}

        self.logger.info(json.dumps(event))

Correlation Identifiers

Include correlation IDs that enable tracking user sessions, transaction flows, and related events across distributed systems.

{
    "@timestamp": "2025-06-28T18:15:22.000Z",
    "event": {
        "category": ["web"],
        "type": ["access"]
    },
    "trace": {
        "id": "abc123def456"
    },
    "transaction": {
        "id": "txn_789xyz"
    },
    "session": {
        "id": "sess_456abc"
    },
    "user": {
        "id": "user_12345"
    }
}

Sensitive Data Protection

Never log sensitive information directly. Use hashing, tokenization, or redaction techniques while maintaining investigative utility.

Example in Python
import hashlib
from datetime import datetime, timezone

def safe_log_user_activity(user_email, sensitive_data):
    # Hash PII for correlation without exposure
    user_hash = hashlib.sha256(user_email.encode()).hexdigest()[:16]

    event = {
        "@timestamp": datetime.now(timezone.utc).isoformat(),
        "event": {
            "category": ["web"],
            "type": ["access"]
        },
        "user": {
            "hash": user_hash  # Can correlate without exposing email
        },
        "url": {
            "path": "/api/sensitive-endpoint"
        },
    }

    # Never log the actual sensitive data
    logger.info(json.dumps(event))

Performance and Volume Considerations

Smart Sampling

Not every event needs to be logged at the same verbosity level. Implement intelligent sampling based on risk and business criticality.

Example in Python
import random

class AdaptiveLogger:
    def __init__(self):
        self.high_risk_sample_rate = 1.0      # Log 100% of high-risk events
        self.normal_sample_rate = 0.1         # Log 10% of normal events
        self.debug_sample_rate = 0.01         # Log 1% of debug events

    def should_log(self, risk_level):
        if risk_level == "high":
            return True
        elif risk_level == "normal":
            return random.random() < self.normal_sample_rate
        else:
            return random.random() < self.debug_sample_rate

Asynchronous Logging

Prevent logging from impacting application performance by using asynchronous logging mechanisms.

Example in Python
import asyncio
import aiofiles
import json

class AsyncSecurityLogger:
    def __init__(self):
        self.log_queue = asyncio.Queue()

    async def log_event_async(self, event_data):
        await self.log_queue.put(event_data)

    async def process_logs(self):
        while True:
            try:
                event = await asyncio.wait_for(
                    self.log_queue.get(), timeout=1.0
                )
                await self._write_log(event)
            except asyncio.TimeoutError:
                continue

    async def _write_log(self, event):
        async with aiofiles.open('security.log', 'a') as f:
        await f.write(json.dumps(event) + '\n')

Integration and Monitoring

Health Monitoring

Monitor your logging infrastructure itself to ensure security events aren't lost during critical incidents.

Example of the log that contains Health Monitoring

{
    "@timestamp": "2025-06-28T19:30:15.000Z",
    "event": {
        "category": ["system"],
        "type": ["info"]
    },
    "service": {
        "name": "logging_service"
    },
    "metrics": {
        "events_per_second": 1250,
        "queue_depth": 42,
        "dropped_events": 0
    },
    "labels": {
        "monitoring": "logging_health"
    }
}

Alert-Worthy Events

Design logs with alerting in mind. Include fields that enable automated threat detection and response.

Example of Alert-Worthy Event

{
    "@timestamp": "2025-06-28T20:45:30.000Z",
    "event": {
        "category": ["authentication"],
        "type": ["start"],
        "outcome": "failure"
    },
    "rule": {
        "name": "multiple_failed_logins",
        "description": "5+ failed logins in 5 minutes"
    },
    "user": {
        "name": "admin_user"
    },
    "source": {
        "ip": "203.0.113.100"
    },
    "labels": {
        "alert_priority": "high",
    }
}

Conclusion

Effective security logging is both an art and a science. By following these principles (structured formatting, ECS compliance, contextual enrichment, and performance optimization) you'll create logs that serve as powerful tools for security operations teams.

Remember that logging is not just about recording events; it's about enabling rapid detection, investigation, and response to security threats. Every log entry should tell a story that helps protect your organization's assets and users.

The investment in proper logging architecture pays dividends when incidents occur. Security teams armed with well-structured, comprehensive logs can respond to threats in minutes rather than hours, often making the difference between a minor security event and a major breach.

Start implementing these practices incrementally, focusing first on your most critical authentication and authorization flows, then expanding to cover network activity, file operations, and application-specific security events. Your future incident response team will thank you.