AmirFT.Http.CurlLogging
1.0.2
dotnet add package AmirFT.Http.CurlLogging --version 1.0.2
NuGet\Install-Package AmirFT.Http.CurlLogging -Version 1.0.2
<PackageReference Include="AmirFT.Http.CurlLogging" Version="1.0.2" />
<PackageVersion Include="AmirFT.Http.CurlLogging" Version="1.0.2" />
<PackageReference Include="AmirFT.Http.CurlLogging" />
paket add AmirFT.Http.CurlLogging --version 1.0.2
#r "nuget: AmirFT.Http.CurlLogging, 1.0.2"
#:package AmirFT.Http.CurlLogging@1.0.2
#addin nuget:?package=AmirFT.Http.CurlLogging&version=1.0.2
#tool nuget:?package=AmirFT.Http.CurlLogging&version=1.0.2
<p align="center"> <img src="https://img.shields.io/nuget/v/AmirFT.Http.CurlLogging?style=for-the-badge&logo=nuget&logoColor=white&color=004880" alt="NuGet Version" /> <img src="https://img.shields.io/nuget/dt/AmirFT.Http.CurlLogging?style=for-the-badge&logo=nuget&logoColor=white&color=004880" alt="NuGet Downloads" /> <img src="https://img.shields.io/github/license/Am1rFT/CurlLogging?style=for-the-badge&color=yellow" alt="License" /> </p>
<h1 align="center">AmirFT.Http.CurlLogging</h1>
<p align="center"> <strong>Transform your HTTP requests into ready-to-use cURL commands</strong> </p>
<p align="center"> A lightweight <code>DelegatingHandler</code> that automatically logs all HttpClient requests as cURL commands.<br/> Perfect for debugging, API documentation, and reproducing issues. </p>
Why I Built This
I've been there — multiple times in production, dealing with errors from third-party APIs. The support team asks: "Can you send us the cURL command to reproduce the issue?"
And I didn't have it.
Manually reconstructing HTTP requests as cURL commands is tedious and error-prone. So I built this library to solve that problem once and for all. Now every HTTP request my applications make is automatically logged as a ready-to-use cURL command. When issues arise, I just grab the command from the logs and share it — no more guesswork.
Features
- Zero Configuration - Just add the handler and start logging
- Full Request Capture - Headers, body, and query parameters
- Copy & Paste Ready - Output commands work directly in terminal
- Response Logging - Logs response status, headers, body, and elapsed time
- Request Timing - Track how long each HTTP request takes
- Error Tracking - Logs failed requests with timing information
- Sensitive Data Redaction - Automatically redacts passwords, tokens, API keys, credit cards, and more
- Multi-Framework Support - .NET Standard 2.0, .NET 6, .NET 8, .NET 10
Installation
dotnet add package AmirFT.Http.CurlLogging
Package Manager:
Install-Package AmirFT.Http.CurlLogging
Quick Start
With Dependency Injection (Recommended)
// Program.cs or Startup.cs
services.AddTransient<CurlLoggingHandler>();
services.AddHttpClient("MyApi")
.AddHttpMessageHandler<CurlLoggingHandler>();
Direct Usage
var logger = loggerFactory.CreateLogger<CurlLoggingHandler>();
var handler = new CurlLoggingHandler(logger)
{
InnerHandler = new HttpClientHandler()
};
using var client = new HttpClient(handler);
await client.PostAsync("https://api.example.com/users", content);
Output Example
When you make an HTTP request:
await client.PostAsync("https://api.example.com/users",
new StringContent("{\"name\":\"John\"}", Encoding.UTF8, "application/json"));
You'll see this in your logs:
Request (cURL command):
curl -X POST 'https://api.example.com/users' \
-H 'Content-Type: application/json; charset=utf-8' \
-d '{"name":"John"}'
Response:
HTTP Response from https://api.example.com/users in 145ms - Status: 200
Headers:
Content-Type: application/json; charset=utf-8
Content-Length: 42
Body:
{"id":123,"name":"John","created":true}
Response Logging
By default, the handler logs both requests and responses. Response logging includes:
- Status Code - HTTP status code (200, 404, 500, etc.)
- Elapsed Time - How long the request took in milliseconds
- Headers - All response headers
- Body - Response body content (with sensitive data redacted)
Disable Response Logging
If you only want the cURL command without response details:
var options = new CurlLoggingOptions
{
LogResponse = false
};
var handler = new CurlLoggingHandler(logger, options);
Error Handling
When a request fails (throws an exception), the handler logs:
- The target URI
- Elapsed time before failure
- The exception details
This helps you identify slow or failing third-party API calls.
Sensitive Data Redaction
By default, sensitive information is automatically redacted from logs to prevent accidental exposure of credentials and personal data.
What Gets Redacted
| Category | Examples |
|---|---|
| Headers | Authorization, X-API-Key, X-Auth-Token, Cookie, X-CSRF-Token |
| Query Parameters | api_key, token, password, secret, access_token, code |
| Body Fields | password, apiKey, token, credit_card, cvv, ssn, username, email |
Example Output
// Request with sensitive data
await client.PostAsync("https://api.example.com/login?api_key=secret123",
new StringContent("{\"username\":\"john\",\"password\":\"mypassword\"}",
Encoding.UTF8, "application/json"));
Logged output (with redaction):
curl -X POST 'https://api.example.com/login?api_key=[REDACTED]' \
-H 'Authorization: [REDACTED]' \
-H 'Content-Type: application/json; charset=utf-8' \
-d '{"username":"[REDACTED]","password":"[REDACTED]"}'
Configuration Options
var options = new CurlLoggingOptions
{
// Enable/disable redaction (default: true)
EnableRedaction = true,
// Enable/disable response logging (default: true)
LogResponse = true,
// Custom placeholder text (default: "[REDACTED]")
RedactedPlaceholder = "***",
// Add custom sensitive headers
AdditionalSensitiveHeaders = new[] { "X-Custom-Secret" },
// Completely exclude headers from output
ExcludedHeaders = new[] { "X-Internal-Header" },
// Add custom sensitive query parameters
AdditionalSensitiveQueryParams = new[] { "session_id" },
// Add custom sensitive body fields
AdditionalSensitiveBodyFields = new[] { "social_security_number", "bank_account" }
};
var handler = new CurlLoggingHandler(logger, options);
With Dependency Injection
// Register with custom options
services.AddSingleton(new CurlLoggingOptions
{
RedactedPlaceholder = "***",
AdditionalSensitiveHeaders = new[] { "X-Custom-Auth" }
});
services.AddTransient<CurlLoggingHandler>();
services.AddHttpClient("MyApi")
.AddHttpMessageHandler<CurlLoggingHandler>();
Disable Redaction
If you need to see the full request data (e.g., in development):
var options = CurlLoggingOptions.NoRedaction;
var handler = new CurlLoggingHandler(logger, options);
Supported Frameworks
| Framework | Version |
|---|---|
| .NET Standard | 2.0+ |
| .NET | 6.0+ |
| .NET | 8.0+ |
| .NET | 10.0+ |
Contributing
Contributions are welcome! Feel free to:
- Report bugs
- Suggest features
- Submit pull requests
License
This project is licensed under the MIT License - see the LICENSE file for details.
<p align="center"> Made with ❤️ by <a href="https://github.com/AmirFT">AmirFT</a> </p>
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Bcl.AsyncInterfaces (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
-
net10.0
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
-
net6.0
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
-
net8.0
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.