Updated
This commit is contained in:
@@ -3585,6 +3585,357 @@ finally
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Complete Code Examples
|
||||||
|
|
||||||
|
### Example 1: Production ASP.NET Core Application
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using EonaCat.LogStack;
|
||||||
|
|
||||||
|
// In Program.cs
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
// Add EonaCat logging
|
||||||
|
builder.Services.AddEonaCatLogging(config =>
|
||||||
|
{
|
||||||
|
config
|
||||||
|
.WithApplicationName("MyApi")
|
||||||
|
.WithMinimumLevel(LogLevel.Information)
|
||||||
|
.WriteToConsole(useColors: true)
|
||||||
|
.WriteToFile(
|
||||||
|
directory: "./logs",
|
||||||
|
maxFileSize: 100 * 1024 * 1024,
|
||||||
|
maxDirectorySize: 5L * 1024 * 1024 * 1024,
|
||||||
|
compression: CompressionFormat.GZip)
|
||||||
|
.WriteToSlack(
|
||||||
|
webhookUrl: builder.Configuration["Slack:WebhookUrl"],
|
||||||
|
minimumLevel: LogLevel.Error)
|
||||||
|
.WriteToElasticSearch(
|
||||||
|
elasticSearchUrl: builder.Configuration["Elasticsearch:Url"],
|
||||||
|
indexName: "myapi-logs")
|
||||||
|
.BoostWithMachineName()
|
||||||
|
.BoostWithProcessId()
|
||||||
|
.BoostWithCorrelationId()
|
||||||
|
.BoostWithCallerInfo();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Enable advanced telemetry
|
||||||
|
builder.Services.AddEonaCatNamedLoggers(new LoggerDIOptions
|
||||||
|
{
|
||||||
|
EnableTelemetry = true,
|
||||||
|
EnableTracing = true,
|
||||||
|
EnablePerformanceMonitoring = true,
|
||||||
|
EnableHealthMonitoring = true
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.AddEonaCatTracing();
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
app.UseRouting();
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseAuthorization();
|
||||||
|
app.MapControllers();
|
||||||
|
|
||||||
|
var logger = app.Services.GetRequiredService<ILoggerFactory>()
|
||||||
|
.CreateLogger("Application");
|
||||||
|
|
||||||
|
logger.Information("Application starting",
|
||||||
|
("Version", "1.0.0"),
|
||||||
|
("Environment", app.Environment.EnvironmentName));
|
||||||
|
|
||||||
|
app.Run();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 2: Console Application with Multiple Flows
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using EonaCat.LogStack;
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static async Task Main(string[] args)
|
||||||
|
{
|
||||||
|
await using var logger = new LogBuilder("ConsoleApp")
|
||||||
|
.WithMinimumLevel(LogLevel.Debug)
|
||||||
|
.WithTimestampMode(TimestampMode.Utc)
|
||||||
|
.WriteToConsole(useColors: true)
|
||||||
|
.WriteToFile("./logs", filePrefix: "app", maxFileSize: 50 * 1024 * 1024)
|
||||||
|
.WriteToAudit("./audit", auditLevel: AuditLevel.WarningAndAbove)
|
||||||
|
.WriteToMemory(capacity: 100)
|
||||||
|
.WriteToEmail(
|
||||||
|
smtpHost: "smtp.gmail.com", smtpPort: 587, useSsl: true,
|
||||||
|
username: "email@gmail.com", password: "app-password",
|
||||||
|
from: "logs@company.com", to: "admin@company.com",
|
||||||
|
subjectPrefix: "[CRITICAL]", minimumLevel: LogLevel.Critical)
|
||||||
|
.RedisFlow(host: "redis.local", channel: "myapp:logs")
|
||||||
|
.BoostWithMachineName()
|
||||||
|
.BoostWithProcessId()
|
||||||
|
.BoostWithCorrelationId()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
logger.Information("Application started");
|
||||||
|
await ProcessDataAsync(logger);
|
||||||
|
logger.Information("Application completed successfully");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Critical(ex, "Unhandled exception");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await logger.FlushAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async Task ProcessDataAsync(ILogger logger)
|
||||||
|
{
|
||||||
|
logger.Information("Processing started");
|
||||||
|
logger.Debug("Starting batch", ("BatchId", 123), ("Count", 5000));
|
||||||
|
await Task.Delay(1000);
|
||||||
|
logger.Information("Batch processed", ("Imported", 4998), ("Errors", 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 3: Service with Dependency Injection & Telemetry
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using EonaCat.LogStack;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
public class OrderService
|
||||||
|
{
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
private readonly ITelemetryAggregator _telemetry;
|
||||||
|
private readonly ISpanFactory _spans;
|
||||||
|
|
||||||
|
public OrderService(ILogger logger, ITelemetryAggregator telemetry, ISpanFactory spans)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_telemetry = telemetry;
|
||||||
|
_spans = spans;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Order> ProcessOrderAsync(string orderId, decimal amount)
|
||||||
|
{
|
||||||
|
using var span = _spans.CreateSpanScope("ProcessOrder");
|
||||||
|
span.SetAttribute("OrderId", orderId);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Information("Processing order", ("OrderId", orderId), ("Amount", amount));
|
||||||
|
_telemetry.RecordCounter("orders.started", 1);
|
||||||
|
|
||||||
|
var order = new Order { Id = orderId, Amount = amount };
|
||||||
|
await Task.Delay(500);
|
||||||
|
|
||||||
|
_logger.Information("Order processed", ("Status", "Completed"));
|
||||||
|
_telemetry.RecordCounter("orders.completed", 1);
|
||||||
|
_telemetry.RecordGauge("order.revenue", amount);
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_telemetry.RecordCounter("orders.failed", 1);
|
||||||
|
span.RecordException(ex);
|
||||||
|
_logger.Error(ex, "Order processing failed", ("OrderId", orderId));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static async Task Main(string[] args)
|
||||||
|
{
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
|
||||||
|
services.AddEonaCatLogging(config =>
|
||||||
|
{
|
||||||
|
config
|
||||||
|
.WithApplicationName("OrderService")
|
||||||
|
.WriteToConsole()
|
||||||
|
.WriteToFile("./logs")
|
||||||
|
.WriteToDatabase(
|
||||||
|
connectionFactory: () => new SqlConnection("Server=.;Database=Logs;"),
|
||||||
|
tableName: "OrderLogs")
|
||||||
|
.BoostWithCorrelationId();
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddEonaCatTelemetryAggregation();
|
||||||
|
services.AddEonaCatTracing();
|
||||||
|
services.AddScoped<OrderService>();
|
||||||
|
|
||||||
|
var sp = services.BuildServiceProvider();
|
||||||
|
var orderService = sp.GetRequiredService<OrderService>();
|
||||||
|
var order = await orderService.ProcessOrderAsync("ORD-001", 99.99m);
|
||||||
|
|
||||||
|
var telemetry = sp.GetRequiredService<ITelemetryAggregator>();
|
||||||
|
var snapshot = telemetry.GetSnapshot();
|
||||||
|
Console.WriteLine($"Completed: {snapshot.RecordedMetrics["orders.completed"]}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
record Order { public required string Id { get; init; } public required decimal Amount { get; init; } }
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 4: Advanced Resilience Patterns
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using EonaCat.LogStack;
|
||||||
|
|
||||||
|
await using var logger = new LogBuilder("ResilientApp")
|
||||||
|
.WriteToConsole()
|
||||||
|
// Retry with exponential backoff
|
||||||
|
.WriteToRetry(
|
||||||
|
primary: cfg => cfg.WriteToHttp("https://primary-logs.company.com/ingest", batchSize: 50),
|
||||||
|
maxRetries: 3, initialDelayMs: 1000, maxDelayMs: 30000)
|
||||||
|
// Failover to secondary
|
||||||
|
.WriteToFailover(
|
||||||
|
primary: cfg => cfg.WriteToElasticSearch("https://es-primary.company.com:9200", "logs"),
|
||||||
|
secondary: cfg => cfg.WriteToFile("./logs/failover"),
|
||||||
|
recoveryCheckIntervalSeconds: 60)
|
||||||
|
// Rate limiting with deduplication
|
||||||
|
.WriteToThrottled(
|
||||||
|
target: cfg => cfg.WriteToSlack("https://hooks.slack.com/...", LogLevel.Warning),
|
||||||
|
requestsPerSecond: 10, enableDeduplication: true, minimumLevel: LogLevel.Warning)
|
||||||
|
// Circuit breaker
|
||||||
|
.WriteToCircuitBreaker(
|
||||||
|
inner: cfg => cfg.WriteToDatabase(() => new SqlConnection("..."), "Logs"),
|
||||||
|
failureThreshold: 5, successThresholdToClose: 3, timeoutSeconds: 60)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
logger.Information("Started with resilience");
|
||||||
|
logger.Error(new Exception("Test"), "Error occurred");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 5: Remote Logging with LogClient
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using EonaCat.LogStack.LogClient;
|
||||||
|
|
||||||
|
var clientOptions = new LogCentralOptions
|
||||||
|
{
|
||||||
|
ServerUrl = "https://logcentral.company.com",
|
||||||
|
ApiKey = "your-api-key",
|
||||||
|
ApplicationName = "DistributedService",
|
||||||
|
ApplicationVersion = "2.1.0",
|
||||||
|
Environment = "Production",
|
||||||
|
BatchSize = 100,
|
||||||
|
FlushIntervalSeconds = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
await using var logger = new LogBuilder("DistributedApp")
|
||||||
|
.WriteToConsole()
|
||||||
|
.WriteToFile("./logs")
|
||||||
|
.WriteToHttp(
|
||||||
|
endpoint: $"{clientOptions.ServerUrl}/api/logs/ingest",
|
||||||
|
batchSize: clientOptions.BatchSize,
|
||||||
|
headers: new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
["X-API-Key"] = clientOptions.ApiKey,
|
||||||
|
["X-App-Name"] = clientOptions.ApplicationName
|
||||||
|
})
|
||||||
|
.BoostWithMachineName()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
logger.Information("Connected to central logging", ("Server", clientOptions.ServerUrl));
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 6: Log Processing and Analysis
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using EonaCat.LogStack;
|
||||||
|
|
||||||
|
await using var logger = new LogBuilder("AnalysisApp")
|
||||||
|
.WriteToConsole()
|
||||||
|
.WriteToMemory(capacity: 10000)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
if (i % 10 == 0)
|
||||||
|
logger.Warning($"Iteration {i}");
|
||||||
|
else
|
||||||
|
logger.Information($"Processing item {i}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var memoryFlow = logger.GetFlowOfType<MemoryFlow>();
|
||||||
|
var events = memoryFlow.GetEvents();
|
||||||
|
|
||||||
|
var errorCount = events.Count(e => e.Level == LogLevel.Error);
|
||||||
|
var warningCount = events.Count(e => e.Level == LogLevel.Warning);
|
||||||
|
Console.WriteLine($"Errors: {errorCount}, Warnings: {warningCount}");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 7: Custom Modifiers for Universal Enrichment
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using EonaCat.LogStack;
|
||||||
|
|
||||||
|
var requestId = "REQ-" + Guid.NewGuid().ToString().Substring(0, 8);
|
||||||
|
var userId = "USER-123";
|
||||||
|
|
||||||
|
await using var logger = new LogBuilder("EnrichedApp")
|
||||||
|
.WriteToConsole()
|
||||||
|
.WriteToFile("./logs")
|
||||||
|
.AddModifier((ref LogEventBuilder builder) =>
|
||||||
|
{
|
||||||
|
builder.WithProperty("RequestId", requestId);
|
||||||
|
builder.WithProperty("UserId", userId);
|
||||||
|
builder.WithProperty("Host", Environment.MachineName);
|
||||||
|
})
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
logger.Information("Operation started");
|
||||||
|
logger.Warning("Potential issue detected");
|
||||||
|
logger.Error(new Exception("Failed"), "Operation failed");
|
||||||
|
|
||||||
|
// All logs automatically include RequestId, UserId, Host
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 8: Structured Logging and Complex Properties
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using EonaCat.LogStack;
|
||||||
|
|
||||||
|
await using var logger = new LogBuilder("StructuredApp")
|
||||||
|
.WriteToConsole()
|
||||||
|
.WriteToFile("./logs", outputFormat: FileOutputFormat.Json)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
// Simple tuple properties (fast)
|
||||||
|
logger.Information("User action",
|
||||||
|
("UserId", 42),
|
||||||
|
("Action", "login"),
|
||||||
|
("Ip", "192.168.1.1"));
|
||||||
|
|
||||||
|
// Dictionary properties
|
||||||
|
var contextDict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "OrderId", "ORD-123" },
|
||||||
|
{ "Items", 5 },
|
||||||
|
{ "Total", 199.99m }
|
||||||
|
};
|
||||||
|
logger.Information("Order processed", contextDict);
|
||||||
|
|
||||||
|
// Exception with context
|
||||||
|
try
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Database connection failed");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Error(ex, "Operation failed",
|
||||||
|
("Retries", 3),
|
||||||
|
("TimeoutMs", 5000),
|
||||||
|
("DatabaseName", "ProductDb"));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Debugging Logging Problems
|
## Debugging Logging Problems
|
||||||
|
|
||||||
Check diagnostics first:
|
Check diagnostics first:
|
||||||
@@ -3607,380 +3958,4 @@ If events are missing:
|
|||||||
4. Check remote destination connectivity.
|
4. Check remote destination connectivity.
|
||||||
5. Enable retry/failover.
|
5. Enable retry/failover.
|
||||||
|
|
||||||
## Summary
|
---
|
||||||
|
|
||||||
EonaCat.LogStack combines:
|
|
||||||
|
|
||||||
- High performance logging
|
|
||||||
- Structured events
|
|
||||||
- Multi-target flows
|
|
||||||
- Runtime telemetry
|
|
||||||
- Distributed tracing support
|
|
||||||
- Diagnostics
|
|
||||||
- Resilience features
|
|
||||||
- Security-focused audit logging
|
|
||||||
|
|
||||||
The library is designed to scale from small console tools to distributed production services.
|
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Complete Code Examples
|
|
||||||
|
|
||||||
### Example 1: Production ASP.NET Core Application
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using EonaCat.LogStack;
|
|
||||||
|
|
||||||
// In Program.cs
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
|
||||||
|
|
||||||
// Add EonaCat logging
|
|
||||||
builder.Services.AddEonaCatLogging(config =>
|
|
||||||
{
|
|
||||||
config
|
|
||||||
.WithApplicationName("MyApi")
|
|
||||||
.WithMinimumLevel(LogLevel.Information)
|
|
||||||
.WriteToConsole(useColors: true)
|
|
||||||
.WriteToFile(
|
|
||||||
directory: "./logs",
|
|
||||||
maxFileSize: 100 * 1024 * 1024,
|
|
||||||
maxDirectorySize: 5L * 1024 * 1024 * 1024,
|
|
||||||
compression: CompressionFormat.GZip)
|
|
||||||
.WriteToSlack(
|
|
||||||
webhookUrl: builder.Configuration["Slack:WebhookUrl"],
|
|
||||||
minimumLevel: LogLevel.Error)
|
|
||||||
.WriteToElasticSearch(
|
|
||||||
elasticSearchUrl: builder.Configuration["Elasticsearch:Url"],
|
|
||||||
indexName: "myapi-logs")
|
|
||||||
.BoostWithMachineName()
|
|
||||||
.BoostWithProcessId()
|
|
||||||
.BoostWithCorrelationId()
|
|
||||||
.BoostWithCallerInfo();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Enable advanced telemetry
|
|
||||||
builder.Services.AddEonaCatNamedLoggers(new LoggerDIOptions
|
|
||||||
{
|
|
||||||
EnableTelemetry = true,
|
|
||||||
EnableTracing = true,
|
|
||||||
EnablePerformanceMonitoring = true,
|
|
||||||
EnableHealthMonitoring = true
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Services.AddEonaCatTracing();
|
|
||||||
|
|
||||||
var app = builder.Build();
|
|
||||||
app.UseHttpsRedirection();
|
|
||||||
app.UseRouting();
|
|
||||||
app.UseAuthentication();
|
|
||||||
app.UseAuthorization();
|
|
||||||
app.MapControllers();
|
|
||||||
|
|
||||||
var logger = app.Services.GetRequiredService<ILoggerFactory>()
|
|
||||||
.CreateLogger("Application");
|
|
||||||
|
|
||||||
logger.Information("Application starting",
|
|
||||||
("Version", "1.0.0"),
|
|
||||||
("Environment", app.Environment.EnvironmentName));
|
|
||||||
|
|
||||||
app.Run();
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example 2: Console Application with Multiple Flows
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using EonaCat.LogStack;
|
|
||||||
|
|
||||||
class Program
|
|
||||||
{
|
|
||||||
static async Task Main(string[] args)
|
|
||||||
{
|
|
||||||
await using var logger = new LogBuilder("ConsoleApp")
|
|
||||||
.WithMinimumLevel(LogLevel.Debug)
|
|
||||||
.WithTimestampMode(TimestampMode.Utc)
|
|
||||||
.WriteToConsole(useColors: true)
|
|
||||||
.WriteToFile("./logs", filePrefix: "app", maxFileSize: 50 * 1024 * 1024)
|
|
||||||
.WriteToAudit("./audit", auditLevel: AuditLevel.WarningAndAbove)
|
|
||||||
.WriteToMemory(capacity: 100)
|
|
||||||
.WriteToEmail(
|
|
||||||
smtpHost: "smtp.gmail.com", smtpPort: 587, useSsl: true,
|
|
||||||
username: "email@gmail.com", password: "app-password",
|
|
||||||
from: "logs@company.com", to: "admin@company.com",
|
|
||||||
subjectPrefix: "[CRITICAL]", minimumLevel: LogLevel.Critical)
|
|
||||||
.RedisFlow(host: "redis.local", channel: "myapp:logs")
|
|
||||||
.BoostWithMachineName()
|
|
||||||
.BoostWithProcessId()
|
|
||||||
.BoostWithCorrelationId()
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
logger.Information("Application started");
|
|
||||||
await ProcessDataAsync(logger);
|
|
||||||
logger.Information("Application completed successfully");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
logger.Critical(ex, "Unhandled exception");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
await logger.FlushAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static async Task ProcessDataAsync(ILogger logger)
|
|
||||||
{
|
|
||||||
logger.Information("Processing started");
|
|
||||||
logger.Debug("Starting batch", ("BatchId", 123), ("Count", 5000));
|
|
||||||
await Task.Delay(1000);
|
|
||||||
logger.Information("Batch processed", ("Imported", 4998), ("Errors", 2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example 3: Service with Dependency Injection & Telemetry
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using EonaCat.LogStack;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
public class OrderService
|
|
||||||
{
|
|
||||||
private readonly ILogger _logger;
|
|
||||||
private readonly ITelemetryAggregator _telemetry;
|
|
||||||
private readonly ISpanFactory _spans;
|
|
||||||
|
|
||||||
public OrderService(ILogger logger, ITelemetryAggregator telemetry, ISpanFactory spans)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_telemetry = telemetry;
|
|
||||||
_spans = spans;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Order> ProcessOrderAsync(string orderId, decimal amount)
|
|
||||||
{
|
|
||||||
using var span = _spans.CreateSpanScope("ProcessOrder");
|
|
||||||
span.SetAttribute("OrderId", orderId);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Information("Processing order", ("OrderId", orderId), ("Amount", amount));
|
|
||||||
_telemetry.RecordCounter("orders.started", 1);
|
|
||||||
|
|
||||||
var order = new Order { Id = orderId, Amount = amount };
|
|
||||||
await Task.Delay(500);
|
|
||||||
|
|
||||||
_logger.Information("Order processed", ("Status", "Completed"));
|
|
||||||
_telemetry.RecordCounter("orders.completed", 1);
|
|
||||||
_telemetry.RecordGauge("order.revenue", amount);
|
|
||||||
return order;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_telemetry.RecordCounter("orders.failed", 1);
|
|
||||||
span.RecordException(ex);
|
|
||||||
_logger.Error(ex, "Order processing failed", ("OrderId", orderId));
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Program
|
|
||||||
{
|
|
||||||
static async Task Main(string[] args)
|
|
||||||
{
|
|
||||||
var services = new ServiceCollection();
|
|
||||||
|
|
||||||
services.AddEonaCatLogging(config =>
|
|
||||||
{
|
|
||||||
config
|
|
||||||
.WithApplicationName("OrderService")
|
|
||||||
.WriteToConsole()
|
|
||||||
.WriteToFile("./logs")
|
|
||||||
.WriteToDatabase(
|
|
||||||
connectionFactory: () => new SqlConnection("Server=.;Database=Logs;"),
|
|
||||||
tableName: "OrderLogs")
|
|
||||||
.BoostWithCorrelationId();
|
|
||||||
});
|
|
||||||
|
|
||||||
services.AddEonaCatTelemetryAggregation();
|
|
||||||
services.AddEonaCatTracing();
|
|
||||||
services.AddScoped<OrderService>();
|
|
||||||
|
|
||||||
var sp = services.BuildServiceProvider();
|
|
||||||
var orderService = sp.GetRequiredService<OrderService>();
|
|
||||||
var order = await orderService.ProcessOrderAsync("ORD-001", 99.99m);
|
|
||||||
|
|
||||||
var telemetry = sp.GetRequiredService<ITelemetryAggregator>();
|
|
||||||
var snapshot = telemetry.GetSnapshot();
|
|
||||||
Console.WriteLine($"Completed: {snapshot.RecordedMetrics["orders.completed"]}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
record Order { public required string Id { get; init; } public required decimal Amount { get; init; } }
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example 4: Advanced Resilience Patterns
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using EonaCat.LogStack;
|
|
||||||
|
|
||||||
await using var logger = new LogBuilder("ResilientApp")
|
|
||||||
.WriteToConsole()
|
|
||||||
// Retry with exponential backoff
|
|
||||||
.WriteToRetry(
|
|
||||||
primary: cfg => cfg.WriteToHttp("https://primary-logs.company.com/ingest", batchSize: 50),
|
|
||||||
maxRetries: 3, initialDelayMs: 1000, maxDelayMs: 30000)
|
|
||||||
// Failover to secondary
|
|
||||||
.WriteToFailover(
|
|
||||||
primary: cfg => cfg.WriteToElasticSearch("https://es-primary.company.com:9200", "logs"),
|
|
||||||
secondary: cfg => cfg.WriteToFile("./logs/failover"),
|
|
||||||
recoveryCheckIntervalSeconds: 60)
|
|
||||||
// Rate limiting with deduplication
|
|
||||||
.WriteToThrottled(
|
|
||||||
target: cfg => cfg.WriteToSlack("https://hooks.slack.com/...", LogLevel.Warning),
|
|
||||||
requestsPerSecond: 10, enableDeduplication: true, minimumLevel: LogLevel.Warning)
|
|
||||||
// Circuit breaker
|
|
||||||
.WriteToCircuitBreaker(
|
|
||||||
inner: cfg => cfg.WriteToDatabase(() => new SqlConnection("..."), "Logs"),
|
|
||||||
failureThreshold: 5, successThresholdToClose: 3, timeoutSeconds: 60)
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
logger.Information("Started with resilience");
|
|
||||||
logger.Error(new Exception("Test"), "Error occurred");
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example 5: Remote Logging with LogClient
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using EonaCat.LogStack.LogClient;
|
|
||||||
|
|
||||||
var clientOptions = new LogCentralOptions
|
|
||||||
{
|
|
||||||
ServerUrl = "https://logcentral.company.com",
|
|
||||||
ApiKey = "your-api-key",
|
|
||||||
ApplicationName = "DistributedService",
|
|
||||||
ApplicationVersion = "2.1.0",
|
|
||||||
Environment = "Production",
|
|
||||||
BatchSize = 100,
|
|
||||||
FlushIntervalSeconds = 5
|
|
||||||
};
|
|
||||||
|
|
||||||
await using var logger = new LogBuilder("DistributedApp")
|
|
||||||
.WriteToConsole()
|
|
||||||
.WriteToFile("./logs")
|
|
||||||
.WriteToHttp(
|
|
||||||
endpoint: $"{clientOptions.ServerUrl}/api/logs/ingest",
|
|
||||||
batchSize: clientOptions.BatchSize,
|
|
||||||
headers: new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
["X-API-Key"] = clientOptions.ApiKey,
|
|
||||||
["X-App-Name"] = clientOptions.ApplicationName
|
|
||||||
})
|
|
||||||
.BoostWithMachineName()
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
logger.Information("Connected to central logging", ("Server", clientOptions.ServerUrl));
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example 6: Log Processing and Analysis
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using EonaCat.LogStack;
|
|
||||||
|
|
||||||
await using var logger = new LogBuilder("AnalysisApp")
|
|
||||||
.WriteToConsole()
|
|
||||||
.WriteToMemory(capacity: 10000)
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
for (int i = 0; i < 100; i++)
|
|
||||||
{
|
|
||||||
if (i % 10 == 0)
|
|
||||||
logger.Warning($"Iteration {i}");
|
|
||||||
else
|
|
||||||
logger.Information($"Processing item {i}");
|
|
||||||
}
|
|
||||||
|
|
||||||
var memoryFlow = logger.GetFlowOfType<MemoryFlow>();
|
|
||||||
var events = memoryFlow.GetEvents();
|
|
||||||
|
|
||||||
var errorCount = events.Count(e => e.Level == LogLevel.Error);
|
|
||||||
var warningCount = events.Count(e => e.Level == LogLevel.Warning);
|
|
||||||
Console.WriteLine($"Errors: {errorCount}, Warnings: {warningCount}");
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example 7: Custom Modifiers for Universal Enrichment
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using EonaCat.LogStack;
|
|
||||||
|
|
||||||
var requestId = "REQ-" + Guid.NewGuid().ToString().Substring(0, 8);
|
|
||||||
var userId = "USER-123";
|
|
||||||
|
|
||||||
await using var logger = new LogBuilder("EnrichedApp")
|
|
||||||
.WriteToConsole()
|
|
||||||
.WriteToFile("./logs")
|
|
||||||
.AddModifier((ref LogEventBuilder builder) =>
|
|
||||||
{
|
|
||||||
builder.WithProperty("RequestId", requestId);
|
|
||||||
builder.WithProperty("UserId", userId);
|
|
||||||
builder.WithProperty("Host", Environment.MachineName);
|
|
||||||
})
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
logger.Information("Operation started");
|
|
||||||
logger.Warning("Potential issue detected");
|
|
||||||
logger.Error(new Exception("Failed"), "Operation failed");
|
|
||||||
|
|
||||||
// All logs automatically include RequestId, UserId, Host
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example 8: Structured Logging and Complex Properties
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using EonaCat.LogStack;
|
|
||||||
|
|
||||||
await using var logger = new LogBuilder("StructuredApp")
|
|
||||||
.WriteToConsole()
|
|
||||||
.WriteToFile("./logs", outputFormat: FileOutputFormat.Json)
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
// Simple tuple properties (fast)
|
|
||||||
logger.Information("User action",
|
|
||||||
("UserId", 42),
|
|
||||||
("Action", "login"),
|
|
||||||
("Ip", "192.168.1.1"));
|
|
||||||
|
|
||||||
// Dictionary properties
|
|
||||||
var contextDict = new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
{ "OrderId", "ORD-123" },
|
|
||||||
{ "Items", 5 },
|
|
||||||
{ "Total", 199.99m }
|
|
||||||
};
|
|
||||||
logger.Information("Order processed", contextDict);
|
|
||||||
|
|
||||||
// Exception with context
|
|
||||||
try
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Database connection failed");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
logger.Error(ex, "Operation failed",
|
|
||||||
("Retries", 3),
|
|
||||||
("TimeoutMs", 5000),
|
|
||||||
("DatabaseName", "ProductDb"));
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Additional Resources
|
|
||||||
|
|
||||||
- **[GitHub Repository](https://git.saey.me/EonaCat/EonaCat.logstack)** - Source code and issues
|
|
||||||
- **[NuGet Package](https://www.nuget.org/packages/EonaCat.LogStack)** - Official package
|
|
||||||
- **[Supported Targets](#supported-targets)** - .NET versions and frameworks
|
|
||||||
- **[Installation](#installation)** - Getting started guide
|
|
||||||
Reference in New Issue
Block a user