You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This issue proposes a few additions so Pulse can show traffic that doesn't go through URLSession, starting with grpc-swift-2 clients, and so it captures request bodies that URLSession streams. I opened the PRs below as drafts so we can agree on the approach here first.
Motivation
gRPC over SwiftNIO doesn't show up. grpc-swift v2, like other SwiftNIO-based clients (Is there a way to get Pulse working with NIO. #291), never touches URLSession. The only public way to log such a task today is LoggerStore.storeRequest, which stores the task once it has finished and skips NetworkLogger's filters and redaction.
swift-openapi-urlsession's request bodies are missing. Its default transport streams bodies through the task delegate's needNewBodyStream, so PulseProxy logs those requests without a body.
What I built
PulseGRPC is a small package with a grpc-swift v2 ClientInterceptor. It logs every RPC as a Pulse network task:
a grpcs://host/package.Service/Method URL and the grpc label
messages as JSON bodies
metadata as headers, plus grpc-status
the duration, sizes and timing, and a failure state.
It lives outside Pulse, so Pulse doesn't need to depend on grpc-swift-2. To fully function, it needs a few changes in Pulse, which I have outlined below.
Proposed changes (draft PRs)
What PulseGRPC needs
Support logging network tasks that don't use URLSession #382: NetworkLogger.logTaskCreated(taskId:…) and logTaskCompleted(taskId:…), for tasks without a URLSessionTask. They're stateless and keyed by a task ID the caller provides. They go through send(_:), so filters, redaction and willHandleEvent apply. A second commit shows the descriptions of custom-domain errors instead of "Error" in the console, partway towards Improved NSURLError/custom network error support #341.
Not opened as PRs, but I have them ready if you want them:
Docs for closeButtonHidden(_:) on consoles pushed onto a navigation stack. ConsoleView shows its close button whenever presentationMode.isPresented is true, and that's also true for pushed views, so they show a close button next to the back button.
.scripts/build.sh ignores -s and build failures, so the iOS and tvOS CI jobs currently build nothing.
A possible follow-up I haven't written yet: contentType looks up headers["Content-Type"] case-sensitively, so a task logged through the new methods with HTTP/2-style lowercase content-type loses its content type, and PulseGRPC has to keep that one header capitalized.
None of the PRs touch CHANGELOG.md. Please let me know if I should add the entries or if you prefer to do that.
Design choices
Bodies are JSON
PulseGRPC stores protobuf messages as JSON with Content-Type: application/json. The viewer, search, sensitiveDataFields, export and Pulse Pro then work unchanged, and the protobuf content-type hooks keep their meaning.
No schema or protocol changes
Tasks are .dataTasks with a grpc:// or grpcs:// URL, a grpc label and a grpc-status header. TaskType, the Core Data model and the remote-logging protocol are untouched, so .pulse files, Pulse for Mac and Pulse Pro keep working.
A stateless API
An alternative is a handle-based API on top: startTask(...) -> TaskHandle with finish(...), a lock, and a deinit that logs an abandoned task as cancelled. It's harder to misuse, but it adds a public type with lifecycle rules. I'm happy to switch if you prefer that.
Streamed bodies use swizzling
In the style PulseProxy already uses: hooks on the app's delegate classes, once per class, and a tee on one shared thread. #383 lists the limitations.
Questions
Would you accept the two NetworkLogger methods, and are you happy with the names?
Should PulseGRPC stay a separate package that the README links to? Or would you rather have it in this repo as its own product, which would add grpc-swift-2 to Package.swift?
This issue proposes a few additions so Pulse can show traffic that doesn't go through
URLSession, starting with grpc-swift-2 clients, and so it captures request bodies thatURLSessionstreams. I opened the PRs below as drafts so we can agree on the approach here first.Motivation
URLSession. The only public way to log such a task today isLoggerStore.storeRequest, which stores the task once it has finished and skipsNetworkLogger's filters and redaction.needNewBodyStream, so PulseProxy logs those requests without a body.What I built
PulseGRPC is a small package with a grpc-swift v2
ClientInterceptor. It logs every RPC as a Pulse network task:grpcs://host/package.Service/MethodURL and thegrpclabelgrpc-statusIt lives outside Pulse, so Pulse doesn't need to depend on grpc-swift-2. To fully function, it needs a few changes in Pulse, which I have outlined below.
Proposed changes (draft PRs)
What PulseGRPC needs
NetworkLogger.logTaskCreated(taskId:…)andlogTaskCompleted(taskId:…), for tasks without aURLSessionTask. They're stateless and keyed by a task ID the caller provides. They go throughsend(_:), so filters, redaction andwillHandleEventapply. A second commit shows the descriptions of custom-domain errors instead of "Error" in the console, partway towards ImprovedNSURLError/custom network error support #341.What swift-openapi-urlsession needs
uploadTask(with:from:),upload(for:from:)) and of streamed uploads (needNewBodyStream), which covers swift-openapi-urlsession. Builds on Fix URLSessionProxy async uploads ignoring the task delegate #381.Fixes found along the way (each one stands on its own)
sensitiveHeadersmatched case-sensitively, so a lowercaseauthorizationdidn't redactAuthorization.responseBodySize = -1.URLSessionProxy's async uploads ignored the task delegate and stayed pending.Not opened as PRs, but I have them ready if you want them:
closeButtonHidden(_:)on consoles pushed onto a navigation stack.ConsoleViewshows its close button wheneverpresentationMode.isPresentedis true, and that's also true for pushed views, so they show a close button next to the back button..scripts/build.shignores-sand build failures, so the iOS and tvOS CI jobs currently build nothing.A possible follow-up I haven't written yet:
contentTypelooks upheaders["Content-Type"]case-sensitively, so a task logged through the new methods with HTTP/2-style lowercasecontent-typeloses its content type, and PulseGRPC has to keep that one header capitalized.None of the PRs touch
CHANGELOG.md. Please let me know if I should add the entries or if you prefer to do that.Design choices
Bodies are JSON
PulseGRPC stores protobuf messages as JSON with
Content-Type: application/json. The viewer, search,sensitiveDataFields, export and Pulse Pro then work unchanged, and the protobuf content-type hooks keep their meaning.No schema or protocol changes
Tasks are
.dataTasks with agrpc://orgrpcs://URL, agrpclabel and agrpc-statusheader.TaskType, the Core Data model and the remote-logging protocol are untouched, so.pulsefiles, Pulse for Mac and Pulse Pro keep working.A stateless API
An alternative is a handle-based API on top:
startTask(...) -> TaskHandlewithfinish(...), a lock, and adeinitthat logs an abandoned task as cancelled. It's harder to misuse, but it adds a public type with lifecycle rules. I'm happy to switch if you prefer that.Streamed bodies use swizzling
In the style PulseProxy already uses: hooks on the app's delegate classes, once per class, and a tee on one shared thread. #383 lists the limitations.
Questions
NetworkLoggermethods, and are you happy with the names?Package.swift?