# =====================================================================================================
# endpoint-logging - complete reference configuration
#
# Every property of the SHARED endpoint-logging namespace (both Limesium modules) with its DEFAULT
# value and the reasoning behind it. Copy the block into an application.yml and change only what you
# need: every value shown here is
# the built-in default, so an entry you leave out (or delete) behaves exactly like an entry you keep.
# Bound by RequestLoggingProperties; invalid values (blank names, non-positive sizes/durations) fail
# the context start with a message naming the property.
# =====================================================================================================

endpoint-logging:
  # Master switch. `false` removes the module entirely - the auto-configuration backs off, no filter,
  # no listener, no beans. This is a context-start decision, not a runtime toggle; for a runtime
  # off-switch use the logger level below instead (a disabled level skips the event assembly too).
  enabled: true

  # Logger the exchange events are emitted on. The level of
  # THIS logger decides which exchanges are visible: INFO shows every exchange, WARN keeps only
  # failures, timeouts and slow requests, ERROR only thrown chains (see `logging.level` below).
  logger-name: endpoint-http-exchange

  # Header the correlation id is read from on TRACELESS exchanges only (ADR-0002): a request with a
  # conformant W3C traceparent takes its request id from the traceparent's trace id, ignores this
  # header, and gets NO echo - the wire stays untouched. On a traceless exchange, absent or blank
  # means a new id is generated (by default a 21-character counting id: random per-instance base-36
  # prefix plus counter, ADR-0004 - override the CorrelationIdGenerator bean to change
  # the format), and the id is echoed back to the client on the response under this same header name -
  # set ONCE at filter entry, before the chain runs; the filter does not re-assert it, so downstream
  # code that sets this header itself or calls HttpServletResponse.reset() decides what the client
  # finally sees, while the event and the MDC keep the id resolved at entry. Whichever identity wins
  # rides the MDC as `endpoint_request_id` while the request is handled. A caller-supplied value is
  # adopted only when it is 1-128 visible-ASCII characters (an opaque token: UUID, base-36, ULID, hex);
  # anything else - whitespace, control or non-ASCII characters, more than 128 characters - counts as
  # absent, so the peer never dictates the length or shape of what reaches every log line.
  correlation-id-header: X-Correlation-Id

  # Whether the query string is logged (as its own field `endpoint_url_query`, never as part of the
  # path - grouping by path must not be defeated by varying queries). Disable when query parameters
  # may carry personal data.
  include-query-string: true

  # Optionally log an ARRIVAL line the moment the request comes in, before the handler runs - useful
  # when long-running or hanging exchanges must be visible while still in flight. The arrival line
  # carries no outcome/status/duration, so dashboards keyed on `endpoint_outcome` still count exactly
  # one line per exchange even with this enabled.
  log-request-start: false

  # URL patterns (Spring PathPattern syntax) that determine for which endpoints the filter is active
  # AT ALL. Empty (the default) means every endpoint; a request is logged when it matches ANY include
  # pattern and NO exclude prefix - an exclude always wins. Both match the path WITHIN the
  # application (a configured context/base path is stripped first, as in Spring's handler mapping).
  # Invalid patterns fail the context start.
  include-path-patterns: []
  #  - /api/**

  # Request-URI prefixes the filter skips entirely - no event, no MDC, no correlation echo. Prefix
  # match against the DECODED request path (percent-encoding resolved, path parameters dropped - the
  # representation the router matches, so an encoded variant cannot slip past). Default is empty
  # (everything is logged); health probes are the typical exclusion:
  exclude-path-prefixes: []
  #  - /actuator/health

  # At or above this duration the exchange escalates from INFO to WARN and is flagged
  # `endpoint_slow: true` - the outcome stays `success`, slowness raises severity, it does not turn a
  # completed exchange into a failure. Duration is measured until the request is fully finished
  # (request occupancy including error rendering), not bare handler time. Compared at millisecond
  # resolution: values below 1ms are rejected at startup.
  slow-request-threshold: 5s

  # Header logging, one section per direction, rendered into one display-only field each
  # (`endpoint_request_headers` / `endpoint_response_headers`). MASKED BY DEFAULT (ADR-0005): what the
  # selection logs is rendered as a fingerprint unless its name is allowed in plaintext, so the debugging
  # move `includes: ["*"]` costs readability, never confidentiality. The four lists and how they combine
  # (case-insensitive matching, exclude beats include, unmasked beats masked, which wildcards are
  # rejected) are the contract of the type `HeaderLogProperties` - its KDoc is the normative text; the
  # keys and defaults are listed here.
  request-headers:
    # Names to log; empty (the default) logs NOTHING, "*" every header the message carries.
    includes: []
    #  - Accept
    #  - "*"
    # Names removed from the included set; no "*" (rejected at startup).
    excludes: []
    #  - Cookie
    # Names whose VALUE is replaced by the HeaderValueMasker bean's rendering - by default a stable
    # `length:hex` fingerprint (keyed with `masking-key` below, or a bean of the host's own). "*" (the
    # default) masks every logged header; an empty list switches masking off.
    masked: ["*"]
    # Names that appear in PLAINTEXT although `masked` covers them; no "*" (rejected at startup).
    unmasked: []
    #  - Accept
    #  - X-Correlation-Id
  response-headers:
    # Same contract as request-headers, applied to the response.
    includes: []
    #  - Content-Type
    excludes: []
    masked: ["*"]
    unmasked: []
    #  - Content-Type

  # Body logging per direction - a MODE, not a switch (ADR-0006): `never` (the default), `on-failure`
  # or `always`. `on-failure` logs the body only for a failed exchange (outcome not `success`, or a 4xx
  # status) - the volume switch; what each mode captures and when it logs is the contract of the type
  # `BodyLogMode` (normative KDoc). The bodies are TEED as they flow - never pre-read, never replayed,
  # so streaming and async behaviour are untouched and the log shows exactly the bytes that actually
  # moved (an unread request body is logged as absent). Fields `endpoint_request_body` /
  # `endpoint_response_body` appear only when bytes flowed.
  log-request-body: never
  log-response-body: never

  # Body SIZE measurement per direction (meters `endpoint.request.body.size` /
  # `endpoint.response.body.size`, tagged by the handler pattern). Deliberately independent of the
  # log-*-body flags - a metric must not appear and disappear with a logging flag. Measure-only
  # installs a count-only tee (nothing buffered); measured is what actually flowed, exact even beyond
  # max-body-bytes. Zero-byte bodies record no sample. The request side additionally records the
  # counter `endpoint.request.body.read` (tag `state` = unread | partial | complete): the tee mirrors
  # what the application CONSUMED, so this is the one signal that tells a body the client sent but the
  # application ignored from a body that was never sent.
  measure-request-body-size: false
  measure-response-body-size: false

  # Capture limit per body, in bytes. Bounds MEMORY, not the exchange: bytes beyond the limit still
  # reach the application respectively the client unchanged - only the logged value is truncated, with
  # an explicit note of the total size.
  max-body-bytes: 16384

  # Keys the masking fingerprint. Empty (the default) keeps the unkeyed length:hash fingerprint; any
  # other value turns it into an HMAC-SHA256 under this key - same shape, same stability under the
  # same key (so correlation across events, twins and the outbound sibling holds as long as they share
  # it), but a log reader without the key can no longer confirm a guessed value by hashing it. A
  # SECRET: supply it like one (environment variable, vault-backed property), never as a literal in a
  # checked-in file; the properties' toString redacts it. Ignored when a host pins its own
  # HeaderValueMasker bean.
  masking-key: ""

logging:
  level:
    # The exchange stream. INFO = every exchange (the default expectation); WARN = only failures,
    # container timeouts and slow requests; ERROR = only exchanges whose chain threw. Severity and
    # semantic are decoupled: dashboards key on the `endpoint_outcome` field, the level only decides
    # how loud - and whether - a line is emitted.
    endpoint-http-exchange: INFO
    # The module's own logger: the immediate WARN breadcrumb when a chain throws (the full ERROR event
    # follows on the exchange logger once the request is destroyed), and errors of the logging itself.
    # Keep at WARN or lower - silencing it hides the breadcrumb.
    eu.inqudium.limesium.servlet.logging: WARN
