< Summary

Information
Class: ArturRios.Logging.StateLogger
Assembly: ArturRios.Logging
File(s): D:\Repositories\dotnet-logging\src\StateLogger.cs
Line coverage
96%
Covered lines: 94
Uncovered lines: 3
Coverable lines: 97
Total lines: 187
Line coverage: 96.9%
Branch coverage
93%
Covered branches: 54
Total branches: 58
Branch coverage: 93.1%
Method coverage
100%
Covered methods: 12
Fully covered methods: 10
Total methods: 12
Method coverage: 100%
Full method coverage: 83.3%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)50%2262.5%
get_TraceId()100%11100%
Trace(...)100%22100%
Debug(...)100%22100%
Info(...)100%22100%
Warn(...)100%22100%
Error(...)100%22100%
Exception(...)75%44100%
Critical(...)100%22100%
Fatal(...)100%22100%
ResolveCallerInfo(...)94.44%3636100%
FormatMessageWithTraceId(...)100%22100%

File(s)

D:\Repositories\dotnet-logging\src\StateLogger.cs

#LineLine coverage
 1using ArturRios.Logging.Configuration;
 2using ArturRios.Logging.Factories;
 3using ArturRios.Logging.Interfaces;
 4
 5namespace ArturRios.Logging;
 6
 7/// <summary>
 8/// A logger that extracts caller information from state objects passed with log messages.
 9/// Useful for integration with dependency injection frameworks and structured logging.
 10/// </summary>
 11public class StateLogger : IStateLogger
 12{
 2713    private readonly List<IInternalLogger> _loggers = [];
 14
 15    /// <summary>
 16    /// Gets or sets the trace ID for correlating log entries across related operations.
 17    /// </summary>
 4118    public string? TraceId { get; set; }
 19
 20    /// <summary>
 21    /// Initializes a new instance of the <see cref="StateLogger"/> class with the specified configurations.
 22    /// </summary>
 23    /// <param name="configurations">The list of logger configurations to use.</param>
 2724    public StateLogger(List<LoggerConfiguration> configurations)
 2725    {
 8126        foreach (var config in configurations)
 027        {
 028            _loggers.Add(InternalLoggerFactory.Create(config));
 029        }
 2730    }
 31
 32    /// <summary>
 33    /// Logs a trace-level message with caller information extracted from state.
 34    /// </summary>
 35    /// <param name="message">The message to log.</param>
 36    /// <param name="state">Optional state object containing caller information.</param>
 37    public void Trace(string message, object? state = null)
 338    {
 339        var (fp, mn) = ResolveCallerInfo(state);
 1540        foreach (var logger in _loggers)
 341        {
 342            logger.Trace(FormatMessageWithTraceId(message), fp, mn);
 343        }
 344    }
 45
 46    /// <summary>
 47    /// Logs a debug-level message with caller information extracted from state.
 48    /// </summary>
 49    /// <param name="message">The message to log.</param>
 50    /// <param name="state">Optional state object containing caller information.</param>
 51    public void Debug(string message, object? state = null)
 452    {
 453        var (fp, mn) = ResolveCallerInfo(state);
 2054        foreach (var logger in _loggers)
 455        {
 456            logger.Debug(FormatMessageWithTraceId(message), fp, mn);
 457        }
 458    }
 59
 60    /// <summary>
 61    /// Logs an information-level message with caller information extracted from state.
 62    /// </summary>
 63    /// <param name="message">The message to log.</param>
 64    /// <param name="state">Optional state object containing caller information.</param>
 65    public void Info(string message, object? state = null)
 566    {
 567        var (fp, mn) = ResolveCallerInfo(state);
 2768        foreach (var logger in _loggers)
 669        {
 670            logger.Info(FormatMessageWithTraceId(message), fp, mn);
 671        }
 572    }
 73
 74    /// <summary>
 75    /// Logs a warning-level message with caller information extracted from state.
 76    /// </summary>
 77    /// <param name="message">The message to log.</param>
 78    /// <param name="state">Optional state object containing caller information.</param>
 79    public void Warn(string message, object? state = null)
 380    {
 381        var (fp, mn) = ResolveCallerInfo(state);
 1582        foreach (var logger in _loggers)
 383        {
 384            logger.Warn(FormatMessageWithTraceId(message), fp, mn);
 385        }
 386    }
 87
 88    /// <summary>
 89    /// Logs an error-level message with caller information extracted from state.
 90    /// </summary>
 91    /// <param name="message">The message to log.</param>
 92    /// <param name="state">Optional state object containing caller information.</param>
 93    public void Error(string message, object? state = null)
 394    {
 395        var (fp, mn) = ResolveCallerInfo(state);
 1596        foreach (var logger in _loggers)
 397        {
 398            logger.Error(FormatMessageWithTraceId(message), fp, mn);
 399        }
 3100    }
 101
 102    /// <summary>
 103    /// Logs an exception with caller information extracted from state.
 104    /// </summary>
 105    /// <param name="exception">The exception to log.</param>
 106    /// <param name="state">Optional state object containing caller information.</param>
 107    public void Exception(Exception exception, object? state = null)
 3108    {
 3109        var (fp, mn) = ResolveCallerInfo(state);
 3110        var msg = FormatMessageWithTraceId(exception.ToString() ?? exception.Message);
 15111        foreach (var logger in _loggers)
 3112        {
 3113            logger.Exception(msg, fp, mn);
 3114        }
 3115    }
 116
 117    /// <summary>
 118    /// Logs a critical-level message with caller information extracted from state.
 119    /// </summary>
 120    /// <param name="message">The message to log.</param>
 121    /// <param name="state">Optional state object containing caller information.</param>
 122    public void Critical(string message, object? state = null)
 3123    {
 3124        var (fp, mn) = ResolveCallerInfo(state);
 15125        foreach (var logger in _loggers)
 3126        {
 3127            logger.Critical(FormatMessageWithTraceId(message), fp, mn);
 3128        }
 3129    }
 130
 131    /// <summary>
 132    /// Logs a fatal-level message with caller information extracted from state.
 133    /// </summary>
 134    /// <param name="message">The message to log.</param>
 135    /// <param name="state">Optional state object containing caller information.</param>
 136    public void Fatal(string message, object? state = null)
 3137    {
 3138        var (fp, mn) = ResolveCallerInfo(state);
 15139        foreach (var logger in _loggers)
 3140        {
 3141            logger.Fatal(FormatMessageWithTraceId(message), fp, mn);
 3142        }
 3143    }
 144
 145    private static (string filePath, string methodName) ResolveCallerInfo(object? state)
 27146    {
 27147        string? filePath = null;
 27148        string? methodName = null;
 149
 27150        if (state is not IEnumerable<KeyValuePair<string, object>> pairs)
 7151        {
 7152            return (filePath ?? "unknown", methodName ?? "unknown");
 153        }
 154
 121155        foreach (var (key, value) in pairs)
 40156        {
 40157            if (value is null)
 1158            {
 1159                continue;
 160            }
 161
 39162            if (filePath == null && (string.Equals(key, "CallerFilePath", StringComparison.OrdinalIgnoreCase) ||
 39163                                     string.Equals(key, "FilePath", StringComparison.OrdinalIgnoreCase) ||
 39164                                     string.Equals(key, "callerFilePath", StringComparison.OrdinalIgnoreCase)))
 19165            {
 19166                filePath = value.ToString();
 19167            }
 168
 39169            if (methodName == null && (string.Equals(key, "CallerMemberName", StringComparison.OrdinalIgnoreCase) ||
 39170                                       string.Equals(key, "MemberName", StringComparison.OrdinalIgnoreCase) ||
 39171                                       string.Equals(key, "Method", StringComparison.OrdinalIgnoreCase) ||
 39172                                       string.Equals(key, "callerMemberName", StringComparison.OrdinalIgnoreCase)))
 20173            {
 20174                methodName = value.ToString();
 20175            }
 176
 58177            if (filePath != null && methodName != null) break;
 20178        }
 179
 20180        return (filePath ?? "unknown", methodName ?? "unknown");
 27181    }
 182
 183    private string FormatMessageWithTraceId(string message)
 28184    {
 28185        return !string.IsNullOrEmpty(TraceId) ? $"[{nameof(TraceId)}] {TraceId} | {message}" : message;
 28186    }
 187}