Safeguard
Application Security•

ASVS 5.0 V16.2.1: Put When, Where, Who and What in Every Log

ASVS V16.2.1 requires log entries to carry enough metadata to rebuild a timeline. A structured logging setup with request ids, user ids and tests.

Safeguard Security Team
3 min read

ASVS 5.0 V16.2.1 requires every log entry to include the metadata needed for a detailed investigation: when it happened, where, who was involved and what occurred. It is Level 2. Use structured logs with a fixed set of fields added automatically, not hand written messages.

Why it matters

During an incident you reconstruct a timeline. A line that says "update failed" is useless. A line with a timestamp, service, host, request id, user id, source IP, action and outcome can be joined with other records. Metadata also makes alerts and queries possible.

How to implement it

Define the fields and attach them through middleware so developers cannot forget them.

  • when: timestamp in UTC
  • where: service name, version, host or pod, endpoint
  • who: authenticated user id or service identity, source IP, session id hash
  • what: event name, outcome, resource id, correlation or request id
import logging, json, uuid, contextvars
from datetime import datetime, timezone

ctx = contextvars.ContextVar("ctx", default={})

class JsonFormatter(logging.Formatter):
    def format(self, record):
        base = {
            "ts": datetime.now(timezone.utc).isoformat(),
            "service": "billing-api",
            "level": record.levelname,
            "event": record.getMessage(),
        }
        base.update(ctx.get())          # request_id, user_id, ip, route
        return json.dumps(base, default=str)

handler = logging.StreamHandler()
handler.setFormatter(JsonFormatter())
logging.getLogger().addHandler(handler)

def begin_request(user_id, ip, route):
    ctx.set({"request_id": str(uuid.uuid4()), "user_id": user_id,
             "ip": ip, "route": route})

Call begin_request from one middleware layer, and pass the request id on to downstream services in a header so entries across services share it. Log the user id, not the user's personal details.

How to test it

  1. Trigger a known action, such as changing a password, in a test environment.
  2. Find the log entries it produced in the central store.
  3. Check each for all four categories of metadata.
  4. Follow the request id across services and confirm you can rebuild the sequence.
  5. Add an automated test that parses sample log output and fails if a required field is missing.

Common mistakes

  • Free text messages that must be parsed with regular expressions.
  • Missing user context in background jobs and queue consumers.
  • Different field names in different services, such as uid, user and userId.
  • Logging a name or email where a stable id would do.

Quick check

Is a request id required by the standard?

The standard asks for enough metadata to rebuild a timeline. A correlation id is the most practical way to meet that.

Which level does this belong to?

Level 2.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.