Basic Logging
ByteHide Logger provides six logging levels with simple, intuitive methods. Each level serves different purposes and accepts various parameters for flexible logging. Additionally, ByteHide Logger supports fluent syntax, allowing you to chain multiple features like metadata, context, and tags in a single log call.
Logging Methods Overview
Method | Purpose | Parameters |
---|---|---|
Log.Trace(message) | Most detailed diagnostic information | string message |
Log.Debug(message) | Detailed diagnostic information | string message |
Log.Info(message) | General information messages | string message |
Log.Warn(message, exception) | Warning messages | string message , Exception exception = null |
Log.Error(message, context, exception) | Error messages | string message , object context , Exception exception = null |
Log.Critical(message, exception) | Critical errors | string message , Exception exception = null |
Basic Logging Methods
Trace Level
Use for the most detailed diagnostic information:
Log.Trace("Entering method ProcessOrder");
Log.Trace("Processing item 1 of 10");
Log.Trace("Database connection established");
Debug Level
Use for detailed diagnostic information during development:
Log.Debug("User authentication started");
Log.Debug("Cache miss for key: user_123");
Log.Debug("API response received in 250ms");
Info Level
Use for general information about application flow:
Log.Info("Application started successfully");
Log.Info("User logged in");
Log.Info("Order processed successfully");
Advanced Logging Methods
Warn Level
Use for potential issues that don't stop execution:
// Simple warning
Log.Warn("API rate limit approaching");
// Warning with exception
try
{
// Some operation
}
catch (Exception ex)
{
Log.Warn("Non-critical operation failed, using fallback", ex);
}
Error Level
Use for errors that affect functionality:
// Error with context and exception
try
{
ProcessOrder(orderId);
}
catch (Exception ex)
{
Log.Error("Failed to process order", new { OrderId = orderId, UserId = userId }, ex);
}
// Error with context only
Log.Error("Invalid configuration detected", new { ConfigFile = "appsettings.json", Section = "Database" });
// Error with exception only
Log.Error("Database connection failed", null, ex);
Critical Level
Use for critical errors that may cause application termination:
// Critical error with exception
try
{
InitializeDatabase();
}
catch (Exception ex)
{
Log.Critical("Failed to initialize database - application cannot continue", ex);
Environment.Exit(1);
}
// Critical error without exception
Log.Critical("Out of memory - shutting down");
Fluent Syntax
ByteHide Logger supports fluent syntax, allowing you to combine multiple features in a single, readable chain:
// Combine metadata, context, and tags
Log.WithMetadata("executionTimeMs", 1250)
.WithContext("sqlQuery", "SELECT * FROM Orders WHERE Status = 'Pending'")
.WithTags("database", "performance")
.Warn("Slow database query detected");
// User context with tags
Log.WithContext("orderId", order.Id)
.WithContext("customerId", order.CustomerId)
.WithTags("orders", "critical")
.Error("Order processing failed");
// Multiple metadata and tags
Log.WithMetadata("attemptNumber", 3)
.WithMetadata("responseCode", 503)
.WithContext("apiEndpoint", "/api/payments")
.WithTags("api", "external", "retry")
.Warn("External API retry limit reached");
Learn More About Fluent Syntax
For comprehensive examples and advanced patterns, see Fluent Syntax - Learn how to combine all logging features effectively.
Context Objects
The Error
method accepts an object context
parameter for structured logging:
Simple Context
Log.Error("Payment processing failed", new {
Amount = 99.99,
Currency = "USD",
PaymentMethod = "CreditCard"
}, ex);
Complex Context
var orderContext = new
{
OrderId = order.Id,
CustomerId = order.CustomerId,
Items = order.Items.Select(i => new { i.ProductId, i.Quantity, i.Price }),
TotalAmount = order.Total,
PaymentMethod = order.PaymentMethod,
ShippingAddress = new
{
order.ShippingAddress.Street,
order.ShippingAddress.City,
order.ShippingAddress.Country
}
};
Log.Error("Order processing failed", orderContext, ex);
Custom Objects as Context
public class UserContext
{
public string UserId { get; set; }
public string UserName { get; set; }
public string Role { get; set; }
public DateTime LastLogin { get; set; }
}
var userContext = new UserContext
{
UserId = "user_123",
UserName = "john.doe",
Role = "Admin",
LastLogin = DateTime.UtcNow.AddHours(-2)
};
Log.Error("User action failed", userContext, ex);
Exception Logging
Exception with Context
try
{
var result = await ProcessPaymentAsync(paymentRequest);
}
catch (PaymentException ex)
{
Log.Error("Payment processing failed", new
{
TransactionId = paymentRequest.TransactionId,
Amount = paymentRequest.Amount,
ErrorCode = ex.ErrorCode
}, ex);
}
catch (Exception ex)
{
Log.Critical("Unexpected error during payment processing", ex);
}
Exception Only
try
{
ConnectToDatabase();
}
catch (SqlException ex)
{
Log.Warn("Database connection retry needed", ex);
}
catch (TimeoutException ex)
{
Log.Error("Database connection timeout", null, ex);
}
Practical Examples
Service Layer Logging
public class OrderService
{
public async Task<Order> CreateOrderAsync(CreateOrderRequest request)
{
Log.Info("Creating new order");
Log.Debug("Validating order request");
try
{
var order = new Order(request);
Log.Trace("Order object created");
await _repository.SaveAsync(order);
Log.Info("Order created successfully");
return order;
}
catch (ValidationException ex)
{
Log.Warn("Order validation failed", ex);
throw;
}
catch (Exception ex)
{
Log.Error("Failed to create order", new
{
CustomerId = request.CustomerId,
ItemCount = request.Items?.Count ?? 0
}, ex);
throw;
}
}
}
Controller Logging
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
[HttpPost]
public async Task<IActionResult> CreateUser(CreateUserRequest request)
{
Log.Info("User creation requested");
try
{
var user = await _userService.CreateUserAsync(request);
Log.Info("User created successfully");
return Ok(user);
}
catch (DuplicateUserException ex)
{
Log.Warn("Duplicate user creation attempt", ex);
return Conflict("User already exists");
}
catch (Exception ex)
{
Log.Error("User creation failed", new
{
Email = request.Email,
RequestId = HttpContext.TraceIdentifier
}, ex);
return StatusCode(500, "Internal server error");
}
}
}
Background Service Logging
public class EmailProcessingService : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
Log.Info("Email processing service started");
while (!stoppingToken.IsCancellationRequested)
{
try
{
Log.Trace("Checking for pending emails");
var emails = await GetPendingEmailsAsync();
if (emails.Any())
{
Log.Debug($"Processing {emails.Count} pending emails");
foreach (var email in emails)
{
await ProcessEmailAsync(email);
}
Log.Info($"Processed {emails.Count} emails successfully");
}
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
}
catch (Exception ex)
{
Log.Critical("Email processing service encountered critical error", ex);
await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
}
}
Log.Info("Email processing service stopped");
}
}
Best Practices
Level Selection Guidelines
When to Use Each Level
- Trace: Method entry/exit, loop iterations, detailed flow
- Debug: Variable values, cache hits/misses, intermediate results
- Info: Application milestones, user actions, business events
- Warn: Recoverable errors, deprecated usage, performance issues
- Error: Exceptions, failed operations, data inconsistencies
- Critical: System failures, security breaches, unrecoverable errors
Context Best Practices
// ✅ Good - Structured context
Log.Error("Order processing failed", new
{
OrderId = order.Id,
Stage = "Payment",
Amount = order.Total
}, ex);
// ❌ Avoid - String concatenation
Log.Error($"Order {order.Id} processing failed at Payment stage with amount {order.Total}", null, ex);
// ✅ Good - Relevant context only
Log.Error("Database query failed", new { Query = "GetUserById", UserId = userId }, ex);
// ❌ Avoid - Too much context
Log.Error("Database query failed", entireUserObject, ex);
Performance Considerations
// ✅ Efficient - Simple messages for high-frequency logs
Log.Trace("Method entry");
// ✅ Efficient - Avoid expensive operations in log calls
Log.Debug("Cache lookup completed");
// ❌ Avoid - Expensive operations
Log.Debug($"User data: {JsonSerializer.Serialize(complexUserObject)}");
Next Steps
Now that you understand basic logging, explore these advanced features:
- Exception Handling - Learn proper exception logging with Error and Critical methods
- Fluent Syntax - Combine all logging features effectively
- Data Masking - Protect sensitive information
- User Identification - Associate logs with users
- Correlation IDs - Track requests across services
- Global Properties - Add consistent context to all logs