ISC.Kafka.Logging
1.0.0
dotnet add package ISC.Kafka.Logging --version 1.0.0
NuGet\Install-Package ISC.Kafka.Logging -Version 1.0.0
<PackageReference Include="ISC.Kafka.Logging" Version="1.0.0" />
<PackageVersion Include="ISC.Kafka.Logging" Version="1.0.0" />
<PackageReference Include="ISC.Kafka.Logging" />
paket add ISC.Kafka.Logging --version 1.0.0
#r "nuget: ISC.Kafka.Logging, 1.0.0"
#:package ISC.Kafka.Logging@1.0.0
#addin nuget:?package=ISC.Kafka.Logging&version=1.0.0
#tool nuget:?package=ISC.Kafka.Logging&version=1.0.0
ISC.Kafka.Logging
Lightweight, non-blocking, fail-safe Kafka logging client for .NET.
Why This Package?
The legacy IKafkaProducer has critical issues in production:
| Legacy | ISC.Kafka.Logging | |
|---|---|---|
| Request blocking | await ProduceAsync() blocks the request until Kafka responds or times out (3-5s) |
void ProduceAsync() returns immediately, Kafka delivery happens in background |
| Kafka down | Requests slow down or hang, risk of ThreadPool starvation under load | Zero impact on request latency, messages are silently dropped |
| Exception handling | Logs error but caller must still await |
All exceptions swallowed internally, never propagates |
| Timeout defaults | 3000-5000ms — too high for logging | 500-1000ms — fail fast |
| Configuration | Hardcoded SASL mechanism, values mixed in constructor | Fully configurable via IConfiguration, no hardcoded values |
| Testability | Tightly coupled to Kafka | Pluggable ILogTransport — swap to Console, Null, or custom |
| Credentials | Read directly from IConfiguration in constructor |
Config-driven via IOptions<KafkaOptions>, supports Vault / env vars / User Secrets |
Migration from Legacy
4 steps — minimal code changes
Step 1. Install package
dotnet add package ISC.Kafka.Logging
Step 2. Replace using
- using legacy.Repositories.Kafka;
+ using ISC.Kafka.Logging;
Step 3. Replace DI registration
- services.AddSingleton<IKafkaProducer, KafkaProducer>();
+ services.AddKafkaProducer(configuration.GetSection("Kafka"));
Step 4. Remove await from all ProduceAsync calls
- await _producer.ProduceAsync(message);
+ _producer.ProduceAsync(message);
That's it. Same interface name IKafkaProducer, same method name ProduceAsync. No other code changes needed.
Installation
dotnet add package ISC.Kafka.Logging
<details> <summary>Other install methods</summary>
Package Manager:
Install-Package ISC.Kafka.Logging
PackageReference:
<PackageReference Include="ISC.Kafka.Logging" Version="1.0.0" />
</details>
Compatibility
| Requirement | Version |
|---|---|
| .NET | 8.0+ |
| Confluent.Kafka | 2.14.0 |
| Microsoft.Extensions.Options | 10.0.6 |
| Microsoft.Extensions.DependencyInjection.Abstractions | 10.0.6 |
Quick Start
1. Add configuration
// appsettings.json
{
"Kafka": {
"BootstrapServers": "localhost:9092",
"Topic": "app-logs",
"EnableLogging": true
}
}
2. Register services
builder.Services.AddKafkaProducer(builder.Configuration.GetSection("Kafka"));
3. Inject and use
public class OrderService
{
private readonly IKafkaProducer _producer;
public OrderService(IKafkaProducer producer)
{
_producer = producer;
}
public void CreateOrder(int userId)
{
// Fire-and-forget — returns immediately, Kafka delivery happens in background
_producer.ProduceAsync(new { UserId = userId, Action = "CREATE_ORDER", Timestamp = DateTime.UtcNow });
}
}
Configuration
All options are bound from IConfiguration via KafkaOptions:
| Property | Type | Default | Description |
|---|---|---|---|
BootstrapServers |
string |
(required) | Kafka broker addresses (e.g. host1:9092,host2:9092) |
Topic |
string |
(required) | Kafka topic to send log messages to |
SaslUsername |
string? |
null |
SASL username. When set, enables SASL authentication |
SaslPassword |
string? |
null |
SASL password |
SaslMechanism |
string? |
"Plain" |
SASL mechanism: Plain, ScramSha256, ScramSha512 |
SecurityProtocol |
string? |
"SaslSsl" |
Security protocol: SaslSsl, SaslPlaintext, Ssl, Plaintext |
ClientSoftwareName |
string? |
null |
Identifies the client application on the Kafka broker (for monitoring) |
MessageTimeoutMs |
int |
500 |
Max time (ms) to wait for message delivery |
SocketTimeoutMs |
int |
1000 |
Broker socket timeout (ms) |
RetryBackoffMs |
int |
200 |
Backoff time (ms) between retries |
MessageSendMaxRetries |
int |
1 |
Max delivery retry attempts |
EnableLogging |
bool |
true |
Set to false to disable all log delivery |
SASL/SSL Authentication
When SaslUsername is provided, SASL authentication is enabled. Defaults to SaslMechanism = Plain and SecurityProtocol = SaslSsl if not explicitly configured.
Do not store credentials in
appsettings.jsonor source code. Use one of the methods below to injectSaslUsernameandSaslPasswordintoIConfigurationat runtime.
appsettings.json only contains non-secret values:
{
"Kafka": {
"BootstrapServers": "broker.example.com:9093",
"Topic": "app-logs",
"SaslMechanism": "ScramSha512",
"SecurityProtocol": "SaslPlaintext",
"ClientSoftwareName": "my-service"
}
}
Credentials are supplied separately via any of the following methods. All values merge into the same IConfiguration section and are automatically bound to KafkaOptions — no code changes required.
Option 1: Environment Variables (recommended for containers / CI/CD)
export Kafka__SaslUsername=your-username
export Kafka__SaslPassword=your-password
.NET maps Kafka__SaslUsername (double underscore) to IConfiguration["Kafka:SaslUsername"] automatically.
Option 2: User Secrets (recommended for local development)
dotnet user-secrets init
dotnet user-secrets set "Kafka:SaslUsername" "your-username"
dotnet user-secrets set "Kafka:SaslPassword" "your-password"
Requires AddUserSecrets() in the host builder (included by default in ASP.NET Core Development environment).
Option 3: Vault / Key Vault (recommended for production)
Install the config provider for your secrets manager and register it at startup. Credentials are pushed into IConfiguration before the app starts.
| Provider | NuGet Package |
|---|---|
| HashiCorp Vault | VaultSharp.Extensions.Configuration |
| Azure Key Vault | Azure.Extensions.AspNetCore.Configuration.Secrets |
| AWS Secrets Manager | AWSSDK.Extensions.Configuration.SecretsManager |
Example (Azure Key Vault):
builder.Configuration.AddAzureKeyVault(
new Uri("https://your-vault.vault.azure.net/"),
new DefaultAzureCredential());
Store secrets in the vault with keys Kafka--SaslUsername and Kafka--SaslPassword (double dash -- maps to the : separator).
Recommended Settings by Environment
Development:
{
"Kafka": {
"BootstrapServers": "localhost:9092",
"Topic": "dev-logs",
"MessageTimeoutMs": 1000,
"SocketTimeoutMs": 2000,
"MessageSendMaxRetries": 1
}
}
Production (high-load):
{
"Kafka": {
"BootstrapServers": "broker1:9092,broker2:9092",
"Topic": "prod-logs",
"MessageTimeoutMs": 300,
"SocketTimeoutMs": 500,
"RetryBackoffMs": 100,
"MessageSendMaxRetries": 0
}
}
Transports
The package ships with three built-in transports:
| Transport | Description | Use case |
|---|---|---|
KafkaTransport |
Sends messages to Kafka via Confluent producer | Production (default) |
ConsoleTransport |
Writes messages to Console.WriteLine |
Local development |
NullTransport |
Discards all messages (no-op) | Testing / disable logging |
Using a different transport
// Console output for development
builder.Services.AddKafkaProducer<ConsoleTransport>(builder.Configuration.GetSection("Kafka"));
// Disable logging entirely
builder.Services.AddKafkaProducer<NullTransport>(builder.Configuration.GetSection("Kafka"));
Custom transport
Implement the ILogTransport interface:
public class FileTransport : ILogTransport
{
public async Task SendAsync(string payload)
{
await File.AppendAllTextAsync("logs.txt", payload + Environment.NewLine);
}
}
// Register
builder.Services.AddKafkaProducer<FileTransport>(builder.Configuration.GetSection("Kafka"));
API Reference
IKafkaProducer
public interface IKafkaProducer
{
void ProduceAsync(object message);
}
voidreturn — fire-and-forget by design, cannot beawaitedmessageis serialized to JSON viaSystem.Text.JsonwithJsonSerializerDefaults.Web(camelCase), using runtime type (not declared type)nullmessages are silently ignored- Kafka delivery happens in the background, never blocks the caller
- Serialization or delivery errors are silently swallowed
ILogTransport
public interface ILogTransport
{
Task SendAsync(string payload);
}
payloadis the JSON-serialized string of the log event- Implement this interface to create a custom transport
ServiceCollectionExtensions
// Register with default KafkaTransport
services.AddKafkaProducer(configuration.GetSection("Kafka"));
// Register with custom transport
services.AddKafkaProducer<TTransport>(configuration.GetSection("Kafka"));
Failure Behavior
| Scenario | Behavior |
|---|---|
| Kafka is slow | Message times out and is dropped |
| Kafka is down | Message is dropped |
| Serialization error | Error is swallowed |
| Any exception | Handled internally, never thrown to caller |
The library is designed for best-effort delivery. It should be used for logging, audit trails, and non-critical events — not for transactions that require guaranteed delivery.
Publishing
See PUBLISHING.md for instructions on building and publishing the NuGet package.
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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 was computed. 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. |
-
net8.0
- Confluent.Kafka (>= 2.14.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.6)
- Microsoft.Extensions.Options (>= 10.0.6)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.6)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 100 | 4/16/2026 |