aporat/alamofirenetworkactivitylogger
AlamofireNetworkActivityLogger is a Swift logging library for Alamofire 5+ that prints each finished request as a copy-pasteable cURL command together with the response status, headers, body and timing. It is built on a Swift actor
Features
- Log levels:
.debug,.info, or.off. - cURL generation: outgoing requests are formatted as valid
curlcommands, including headers added by theSessionand any adapters. Streamed and binary bodies are described in a shell comment so the command still runs. - Pretty-printed JSON: JSON response bodies are re-indented with sorted keys. Other text is printed as is; binary bodies are summarized by size.
- Body size cap: response bodies are truncated after 10,240 characters by default. Configurable or unlimited.
- Header redaction: optionally mask headers such as
AuthorizationorSet-Cookie. - Request filtering: skip requests with a
@Sendableclosure. - Pluggable output: each request produces one multi-line string, delivered to
printby default or to a sink you provide, so it can be routed into your own logging framework. - Covers data, upload and download requests. Cancelled requests are skipped unless you opt in.
- Actor-based: all state lives in an
actor; nothing crosses an isolation boundary that is notSendable.
Requirements
- iOS 17+ / macOS 14+ / tvOS 17+ / watchOS 10+ / visionOS 1+
- Swift 6+
- Alamofire 5.11+
Installation
Swift Package Manager
Add the following to your Package.swift:
dependencies: [
.package(url: "https://github.com/aporat/AlamofireNetworkActivityLogger.git", from: "1.0.0")
]Then include "AlamofireNetworkActivityLogger" as a dependency in your target.
Usage
Start Logging
import AlamofireNetworkActivityLogger
Task {
await AlamofireNetworkLogger.shared.startLogging()
}Call this once early in your app's lifecycle, typically only in debug builds. Every Alamofire request that finishes after this point is logged, regardless of which Session issued it.
Stop Logging
Task {
await AlamofireNetworkLogger.shared.stopLogging()
}Log Level
Task {
await AlamofireNetworkLogger.shared.setLevel(.info)
}| Level | Output | |----------|--------------------------------------------------------------| | .debug | cURL command, response headers, body, status code, timing | | .info | HTTP method, URL, status code, timing | | .off | Nothing |
Body Size
Task {
await AlamofireNetworkLogger.shared.setMaxBodyLength(2_000) // characters
await AlamofireNetworkLogger.shared.setMaxBodyLength(nil) // unlimited
}Redact Headers
Header names are matched case-insensitively and apply to both the cURL command and the response headers.
Task {
await AlamofireNetworkLogger.shared.setRedactedHeaders(["Authorization", "Cookie", "Set-Cookie"])
}Skip Requests
Task {
await AlamofireNetworkLogger.shared.setShouldSkip { request in
request.url?.host == "analytics.example.com"
}
}Cancelled Requests
Requests cancelled through Alamofire are not logged by default.
Task {
await AlamofireNetworkLogger.shared.setLogsCancelledRequests(true)
}Route Output Elsewhere
Each finished request is delivered as a single string, so entries never interleave with each other.
Task {
await AlamofireNetworkLogger.shared.setOutput { entry in
myLogger.debug(entry)
}
}Example Output
.debug level:
---------------------
✅ [REQUEST] POST 'https://api.example.com/users'
cURL:
curl -v -X POST -H 'Accept: application/json' -H 'Authorization: <redacted>' -H 'Content-Type: application/json' -d '{"name":"Jane"}' 'https://api.example.com/users'
✅ [RESPONSE] 201 [0.342s]
Headers: [
Content-Type: application/json
]
Body:
{
"id" : 1,
"name" : "Jane"
}
---------------------.info level:
---------------------
✅ POST 'https://api.example.com/users'
✅ [RESPONSE] 201 [0.342s]
---------------------Failed request:
---------------------
❌ [REQUEST] GET 'https://api.example.com/users'
cURL:
curl -v 'https://api.example.com/users'
❌ [RESPONSE] none [0.000s]
⚠️ Error: The Internet connection appears to be offline.
---------------------Contributing
Contributions are welcome! To contribute:
- Fork the repository.
- Create a new branch for your feature or bug fix.
- Commit your changes with clear, descriptive messages.
- Push your branch and open a pull request.
Please ensure your changes include appropriate tests and follow the existing code style.
License
This project is licensed under the MIT License. See the LICENSE file for details.
Package Metadata
Repository: aporat/alamofirenetworkactivitylogger
Default branch: main
README: README.md