Skip to content

feat(http): add http.client.log for logging outgoing HTTP requests#4337

Open
reinkrul wants to merge 3 commits into
masterfrom
feature/http-client-logging
Open

feat(http): add http.client.log for logging outgoing HTTP requests#4337
reinkrul wants to merge 3 commits into
masterfrom
feature/http-client-logging

Conversation

@reinkrul

@reinkrul reinkrul commented Jun 8, 2026

Copy link
Copy Markdown
Member

Summary

Adds a configurable log level for outgoing HTTP requests/responses made by the node, mirroring the existing http.log (which logs incoming/server-side traffic). Reuses the existing http.LogLevel enum and defaults to nothing (no change in behavior unless explicitly enabled).

New config option http.client.log:

Level Behavior
nothing (default) No client logging
metadata Logs request method, URI, response status
metadata-and-body Above + request/response bodies (loggable content types only)

At debug verbosity, request headers are also logged.

How it works

  • Wired up in http.configureClient() via a client.RequestLogger hook on the http/client package (same injection pattern as client.StrictMode).
  • The logging decision is read at request time, not when the client is created. This matters because the HTTP engine is configured last, while other engines (e.g. auth's OpenID4VCI client) build their HTTP clients earlier. A construction-time check would miss those clients entirely. getTransport now always installs a thin loggingTransport indirection that consults RequestLogger per request.
  • Body logging reuses the existing isLoggableContentType filter (JSON-family content types), so binary payloads aren't dumped.

Notes

  • Body content-type filter only logs application/json, application/did+json, application/vc+json, application/x-www-form-urlencoded.
  • A non-2xx response is logged as a normal request + response with the error status — not as a transport failure. The HTTP client request failed line only appears for connection-level errors (refused/TLS/timeout/strict-mode rejection).

Out of scope (flagged, not changed)

The server-side request logger checks logger.Level >= logrus.DebugLevel on a *logrus.Entry (http/requestlogger.go). Entry.Level is always 0 (panic level), so that "log headers at debug" path is effectively dead. The new client logger uses the correct logger.Logger.Level. Server-side left untouched to keep this diff tight; worth a follow-up.

Tests

  • clientlogger_test.go — metadata-only, metadata-and-body, non-loggable content type, debug headers, transport error.
  • client_test.go — regression: client created before RequestLogger is set still logs.
  • engine_test.goconfigureClient wiring per level.

Assisted by AI

reinkrul added 2 commits June 8, 2026 16:01
Adds a configurable log level for outgoing HTTP requests/responses made
by the node, mirroring http.log for incoming traffic. Reuses the existing
http.LogLevel enum (nothing/metadata/metadata-and-body) and defaults to
nothing. Wired up in http.configureClient() via a transport-wrapping hook
on the http client package.

Assisted by AI
The logging transport wrapper was decided when the HTTP client was
created. Engines that build their clients before the HTTP engine is
configured (e.g. auth's OpenID4VCI client) never got the wrapper, since
client.RequestLogger was still nil at construction. The HTTP engine is
registered/configured last, so http.client.log had no effect on those
clients.

Always install a thin loggingTransport indirection in getTransport that
reads RequestLogger per request, mirroring how StrictMode is read at
request time. Clients created before logging is configured now log.

Assisted by AI
@qltysh

qltysh Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

0 new issues

Tool Category Rule Count

Comment thread http/clientlogger.go Fixed
@qltysh

qltysh Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Qlty


Coverage Impact

⬆️ Merging this pull request will increase total coverage on master by 0.03%.

Modified Files with Diff Coverage (5)

RatingFile% DiffUncovered Line #s
Coverage rating: B Coverage rating: B
http/engine.go100.0%
Coverage rating: A Coverage rating: A
http/cmd/cmd.go100.0%
Coverage rating: A Coverage rating: A
http/config.go100.0%
Coverage rating: B Coverage rating: B
http/client/client.go100.0%
New Coverage rating: A
http/clientlogger.go91.5%58-59, 84-85
Total94.0%
🤖 Increase coverage with AI coding...
In the `feature/http-client-logging` branch, add test coverage for this new code:

- `http/clientlogger.go` -- Lines 58-59 and 84-85

🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

Make the log level the single control instead of also depending on the
global debug verbosity:

- Log request and response headers at both 'metadata' and
  'metadata-and-body' (previously headers required debug verbosity).
- Mask credential-bearing request headers (Authorization,
  Proxy-Authorization) so they don't leak into the logs. Response
  WWW-Authenticate is a challenge, not a credential, so it is not masked.

Assisted by AI
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants