Прескочи до съдържанието
Редактирай

Loggers

Loggers (Логери)

Логерите записват информация за работата на програмата, като грешки, предупреждения, информационни съобщения и действия на потребителите. Те са критични за наблюдение, диагностика и отстраняване на проблеми.

ILogger интерфейс

public interface ILogger
{
    void Log(LogLevel level, string message);
    void LogError(string message);
    void LogWarning(string message);
    void LogInfo(string message);
    void LogDebug(string message);
}

public enum LogLevel
{
    Debug,
    Info,
    Warning,
    Error,
    Critical
}

ConsoleLogger

public class ConsoleLogger : ILogger
{
    public void Log(LogLevel level, string message)
    {
        var color = GetColorForLevel(level);
        var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        
        Console.ForegroundColor = color;
        Console.WriteLine($"[{timestamp}] {level}: {message}");
        Console.ResetColor();
    }

    public void LogError(string message) => Log(LogLevel.Error, message);
    public void LogWarning(string message) => Log(LogLevel.Warning, message);
    public void LogInfo(string message) => Log(LogLevel.Info, message);
    public void LogDebug(string message) => Log(LogLevel.Debug, message);

    private ConsoleColor GetColorForLevel(LogLevel level)
    {
        return level switch
        {
            LogLevel.Debug => ConsoleColor.Gray,
            LogLevel.Info => ConsoleColor.White,
            LogLevel.Warning => ConsoleColor.Yellow,
            LogLevel.Error => ConsoleColor.Red,
            LogLevel.Critical => ConsoleColor.DarkRed,
            _ => ConsoleColor.White
        };
    }
}

FileLogger

public class FileLogger : ILogger, IDisposable
{
    private readonly string filePath;
    private readonly StreamWriter writer;
    private readonly object lockObject = new object();

    public FileLogger(string filePath)
    {
        this.filePath = filePath;
        this.writer = new StreamWriter(filePath, true);
    }

    public void Log(LogLevel level, string message)
    {
        var logEntry = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} [{level}] {message}";
        
        lock (lockObject)
        {
            writer.WriteLine(logEntry);
            writer.Flush();
        }
    }

    public void LogError(string message) => Log(LogLevel.Error, message);
    public void LogWarning(string message) => Log(LogLevel.Warning, message);
    public void LogInfo(string message) => Log(LogLevel.Info, message);
    public void LogDebug(string message) => Log(LogLevel.Debug, message);

    public void Dispose()
    {
        writer?.Dispose();
    }
}

Serilog пример

public class SerilogExample
{
    public static void ConfigureSerilog()
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.Console()
            .WriteTo.File("logs/myapp.txt", rollingInterval: RollingInterval.Day)
            .WriteTo.Seq("http://localhost:5341")
            .Enrich.WithProperty("Application", "MyApp")
            .Enrich.WithMachineName()
            .CreateLogger();

        Log.Information("Application Starting");
    }

    public static void LoggingExample()
    {
        try
        {
            throw new Exception("Something went wrong");
        }
        catch (Exception ex)
        {
            Log.Error(ex, "An error occurred");
        }
    }
}

Структурирано логване

public class StructuredLogging
{
    private readonly ILogger<StructuredLogging> _logger;

    public void ProcessOrder(Order order)
    {
        _logger.LogInformation(
            "Processing order {OrderId} for customer {CustomerId} with total {Total:C}",
            order.Id,
            order.CustomerId,
            order.Total);

        try
        {
            // Обработка на поръчката
        }
        catch (Exception ex)
        {
            _logger.LogError(
                ex,
                "Failed to process order {OrderId}. Error: {ErrorMessage}",
                order.Id,
                ex.Message);
        }
    }
}

Логване с контекст

public class ContextualLogging
{
    private readonly ILogger _logger;

    public async Task ProcessUserAction(string userId, string action)
    {
        using (var scope = _logger.BeginScope(new Dictionary<string, object>
        {
            ["UserId"] = userId,
            ["Action"] = action,
            ["SessionId"] = Guid.NewGuid()
        }))
        {
            _logger.LogInformation("Starting user action");
            
            // Действия
            
            _logger.LogInformation("Completed user action");
        }
    }
}

Композитен логер

public class CompositeLogger : ILogger
{
    private readonly ILogger[] loggers;

    public CompositeLogger(params ILogger[] loggers)
    {
        this.loggers = loggers;
    }

    public void Log(LogLevel level, string message)
    {
        foreach (var logger in loggers)
        {
            try
            {
                logger.Log(level, message);
            }
            catch (Exception ex)
            {
                // Логване на грешката в останалите логери
                foreach (var otherLogger in loggers.Where(l => l != logger))
                {
                    otherLogger.LogError($"Logger failed: {ex.Message}");
                }
            }
        }
    }

    public void LogError(string message) => Log(LogLevel.Error, message);
    public void LogWarning(string message) => Log(LogLevel.Warning, message);
    public void LogInfo(string message) => Log(LogLevel.Info, message);
    public void LogDebug(string message) => Log(LogLevel.Debug, message);
}

Добри практики

  1. Нива на логване
// Правилно използване на нивата
logger.LogDebug("Detailed information for debugging");
logger.LogInformation("General information about app operation");
logger.LogWarning("Warning messages for potentially harmful situations");
logger.LogError("Error messages for failures that should be investigated");
logger.LogCritical("Critical errors that require immediate attention");
  1. Структурирани данни
// Лошо
logger.LogInformation($"User {userId} logged in from IP {ipAddress}");

// Добре
logger.LogInformation(
    "User logged in. {UserId} {IpAddress}",
    userId,
    ipAddress);
  1. Обработка на изключения
try
{
    // Код
}
catch (Exception ex)
{
    logger.LogError(
        ex,
        "Operation failed. {ErrorDetails}",
        new { ex.Message, ex.StackTrace });
    throw;
}
  1. Конфигурация
public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureLogging(logging =>
        {
            logging.ClearProviders();
            logging.AddConsole();
            logging.AddDebug();
            logging.AddEventLog();
            logging.SetMinimumLevel(LogLevel.Information);
        });

HashLogger

HashLogger