Documentation

LoggingMiddleware
in package
implements MiddlewareInterface

PSR-3 logging middleware - logs one line per handler invocation (per dispatch attempt), with a level derived from the outcome (info for success, warning for 4xx, error for 5xx or a thrown exception), known- sensitive headers redacted by default, and request/response bodies excluded unless explicitly opted in. Exceptions are logged then re-thrown completely unmodified. No special coupling with RetryMiddleware - see logRetriesTo() for an optional adapter onto its existing onRetry hook.

Tags
category

Pop

author

Nick Sagona, III nick@popphp.org

copyright

Copyright (c) 2009-2026 Nick Sagona, III

license

https://www.popphp.org/license New BSD License

version
6.0.0

Table of Contents

Interfaces

MiddlewareInterface
Client middleware interface - a PSR-15-style interceptor for Client's outbound dispatch. Not a literal PSR-15 implementation: PSR-15's real interfaces are typed to ServerRequestInterface (server-side only) and cannot apply to a Client's outbound RequestInterface flow, so this mirrors PSR-15's shape with the request type swapped.

Properties

$includeBody  : bool
Whether to include (truncated) request/response body content in the log context
$logger  : LoggerInterface
The PSR-3 logger to write to
$maxBodyLength  : int
Maximum body length included in the log context when includeBody is true
$redactedHeaders  : array<string|int, mixed>
Header names redacted from the logged context (case-insensitive match)

Methods

__construct()  : mixed
Constructor
addRedactedHeader()  : LoggingMiddleware
Add a header name to the redacted list
getIncludeBody()  : bool
Get whether body content is included in the log context
getMaxBodyLength()  : int
Get the maximum body length included in the log context
getRedactedHeaders()  : array<string|int, mixed>
Get the redacted header list
logRetriesTo()  : callable
Adapt a PSR-3 logger into a callable matching RetryMiddleware::setOnRetry()'s signature, producing a structured "retrying" warning log per attempt with the failure reason (exception class+message, or response status) and computed delay
process()  : ResponseInterface
Process the request, logging one line for this invocation once the outcome is known
setIncludeBody()  : LoggingMiddleware
Set whether to include (truncated) request/response body content in the log context
setMaxBodyLength()  : LoggingMiddleware
Set the maximum body length included in the log context when includeBody is true
setRedactedHeaders()  : LoggingMiddleware
Set the redacted header list, replacing the defaults
bodyForLog()  : string
Build the (truncated) logged representation of a request/response body without materializing the whole underlying stream into memory - critical for large, file-backed bodies (e.g. multi-megabyte uploads), where only ~maxBodyLength bytes ever need to exist as a PHP string.
buildContext()  : array<string|int, mixed>
Build the structured log context for a request/response/exception outcome
levelForStatus()  : string
Determine the PSR-3 log level for a response status code
redact()  : array<string|int, mixed>
Redact configured header names from a PSR-7 getHeaders()-shaped array
truncate()  : string
Truncate body content to the configured maximum length

Properties

$includeBody

Whether to include (truncated) request/response body content in the log context

protected bool $includeBody = false

$maxBodyLength

Maximum body length included in the log context when includeBody is true

protected int $maxBodyLength = 1000

$redactedHeaders

Header names redacted from the logged context (case-insensitive match)

protected array<string|int, mixed> $redactedHeaders = ['Authorization', 'Cookie', 'Set-Cookie', 'X-Api-Key', 'Proxy-Authorization']

Methods

__construct()

Constructor

public __construct(LoggerInterface $logger) : mixed
Parameters
$logger : LoggerInterface

getIncludeBody()

Get whether body content is included in the log context

public getIncludeBody() : bool
Return values
bool

getMaxBodyLength()

Get the maximum body length included in the log context

public getMaxBodyLength() : int
Return values
int

getRedactedHeaders()

Get the redacted header list

public getRedactedHeaders() : array<string|int, mixed>
Return values
array<string|int, mixed>

logRetriesTo()

Adapt a PSR-3 logger into a callable matching RetryMiddleware::setOnRetry()'s signature, producing a structured "retrying" warning log per attempt with the failure reason (exception class+message, or response status) and computed delay

public static logRetriesTo(LoggerInterface $logger) : callable
Parameters
$logger : LoggerInterface
Return values
callable

bodyForLog()

Build the (truncated) logged representation of a request/response body without materializing the whole underlying stream into memory - critical for large, file-backed bodies (e.g. multi-megabyte uploads), where only ~maxBodyLength bytes ever need to exist as a PHP string.

protected bodyForLog(StreamInterface $body) : string

For a Pop\Http\Body, reads at most maxBodyLength + 1 raw bytes directly off the underlying stream resource (bypassing render()'s encoding/chunk-split transforms, which are irrelevant - and potentially misleading - for a debug log), saving and restoring the stream's read position exactly as Body::getContent() does, so other consumers of the same Body object are unaffected. Non-seekable streams are skipped gracefully with a placeholder rather than letting a rewind()/fseek() PHP warning leak out of a logging call. Any other StreamInterface implementation falls back to the previous whole-body-then-truncate behavior, since there is no generic PSR-7 API for a position-preserving bounded read.

Parameters
$body : StreamInterface
Return values
string

buildContext()

Build the structured log context for a request/response/exception outcome

protected buildContext(RequestInterface $request, ResponseInterface|null $response, Throwable|null $exception, float $duration) : array<string|int, mixed>
Parameters
$request : RequestInterface
$response : ResponseInterface|null
$exception : Throwable|null
$duration : float
Return values
array<string|int, mixed>

levelForStatus()

Determine the PSR-3 log level for a response status code

protected levelForStatus(int $code) : string
Parameters
$code : int
Return values
string

redact()

Redact configured header names from a PSR-7 getHeaders()-shaped array

protected redact(array<string|int, mixed> $headers) : array<string|int, mixed>
Parameters
$headers : array<string|int, mixed>
Return values
array<string|int, mixed>

truncate()

Truncate body content to the configured maximum length

protected truncate(string $content) : string

A negative maxBodyLength is clamped to 0 - mb_substr()/substr() treat a negative length as "omit N characters from the end," not "take N characters," so without clamping, a negative value would silently produce unbounded (merely trailing-trimmed) output that still looks truncated because of the appended '...'.

Uses mb_strlen()/mb_substr() when available for multi-byte-safe truncation, falling back to byte-based strlen()/substr() otherwise - ext-mbstring is only suggested, not required, by this package, so an unconditional mb_* call would fatal on a build without it. The byte-based fallback can split a multi-byte character mid-sequence; that's an accepted, honest degradation rather than a fatal error.

Parameters
$content : string
Return values
string

        
On this page

Search results