Skip to content

feat(network): add logRequest API for traffic that bypasses URLSession (gRPC, custom transports) - #442

Merged
maatheusgois-dd merged 2 commits into
DebugSwift:mainfrom
dimashbk:feat/custom-request-logging
Aug 28, 2026
Merged

maatheusgois-dd merged 2 commits into
DebugSwift:mainfrom
dimashbk:feat/custom-request-logging

Conversation

@dimashbk

@dimashbk dimashbk commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds DebugSwift.Network.shared.logRequest(...) — a public API to log requests that bypass URLSession and are therefore invisible to the swizzler: gRPC over SwiftNIO (grpc-swift), custom sockets, or any hand-rolled transport. Logged entries appear in the Network tab alongside automatically captured traffic.

Today HttpModel and HttpDatasource are internal, so apps using gRPC have no way to surface those calls in DebugSwift. This is a universal entry point rather than a gRPC-specific integration: any transport can feed the Network tab through it.

Approach

The method builds an HttpModel and routes it through the existing pipeline, so behavior matches automatically captured traffic:

  • ignoredURLs / onlyURLs filtering via HttpDatasource.addHttpRequest
  • status-code descriptions via ErrorHelper
  • UI refresh via the existing reloadHttp_DebugSwift notification (same as WKWebViewNetworkMonitor)
  • returns Bool so callers know whether the entry was stored

No changes to existing behavior — purely additive.

Public API

// Example: logging a gRPC call from a grpc-swift client interceptor
DebugSwift.Network.shared.logRequest(
    url: URL(string: "grpc://api.example.com/example.v1.UserService/GetUser")!,
    method: "POST",
    requestHeaders: requestMetadata,
    requestBody: requestJSON.data(using: .utf8),
    responseStatusCode: status.isOk ? 200 : 500,
    responseHeaders: responseMetadata,
    responseBody: responseJSON.data(using: .utf8),
    error: transportError,
    startTime: callStartDate,
    endTime: Date()
)

Type of change

  • Fix
  • Feature
  • Refactor
  • Docs
  • CI/CD

Test plan

  • Unit tests updated
  • Manual testing completed
  • CI passing

Manual test steps

  1. Call DebugSwift.Network.shared.logRequest(...) from a gRPC client interceptor (or any code path outside URLSession).
  2. Open the Network tab — the entry appears in the list with method, status, size and duration, and opens into the standard request detail screen.
  3. Add the host to ignoredURLs and repeat — the entry is filtered out and logRequest returns false.

Tests

NetworkCustomRequestLoggingTests (6 tests): field mapping, error → isSuccess == false, ignoredURLs/onlyURLs filtering, reload notification, zero-duration default.

Test Suite 'NetworkCustomRequestLoggingTests' passed
Executed 6 tests, with 0 failures (0 unexpected)
** TEST SUCCEEDED **

The package also builds in Swift 6 language mode.

Files Changed

  • DebugSwift.Network.swift — new logRequest(...) public method
  • NetworkCustomRequestLoggingTests.swift (new) — 6 tests
  • README.md — "Custom Request Logging (gRPC and other non-URLSession transports)" section with a gRPC interceptor example

Checklist

  • I reviewed my own changes
  • I updated docs when needed
  • I considered backward compatibility

…, custom transports)

DebugSwift's network inspector captures URLSession traffic via swizzling,
but transports that bypass URLSession entirely (gRPC over SwiftNIO,
custom sockets) are invisible to it, and HttpModel/HttpDatasource are
internal, so apps have no way to surface those calls in the Network tab.

Adds DebugSwift.Network.shared.logRequest(...) that builds an HttpModel,
routes it through the existing pipeline (ignoredURLs/onlyURLs filtering,
ErrorHelper status mapping, reloadHttp_DebugSwift UI refresh) and returns
whether the entry was stored.

Includes unit tests and a README section with a gRPC interceptor example.
@dimashbk dimashbk changed the title Add Network.logRequest API for traffic that bypasses URLSession (gRPC, custom transports) feat(network): add logRequest API for traffic that bypasses URLSession (gRPC, custom transports) Aug 19, 2026
HttpDatasource is main-thread-confined (the capture pipeline reports via
@mainactor), but logRequest ran the store on the caller's thread — a data
race when called from gRPC event loops. Off-main calls now evaluate URL
filters synchronously and hop the store+notification to main. Extracts
passesURLFilters from addHttpRequest for reuse.
@dimashbk

Copy link
Copy Markdown
Contributor Author

Pushed a follow-up commit: logRequest now confines the store to the main thread. HttpDatasource is main-confined by the capture pipeline (@MainActor report), so storing on the caller's thread was a data race for callers logging from gRPC event loops. Off-main calls evaluate URL filters synchronously (new HttpDatasource.passesURLFilters, reused by addHttpRequest) and hop the store + reload notification to main; on-main behavior is unchanged, so the existing tests still pass as-is.

@maatheusgois-dd
maatheusgois-dd merged commit b85fd86 into DebugSwift:main Aug 28, 2026
1 check passed
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