< Summary

Information
Class: ArturRios.Logging.StateLogger
Assembly: ArturRios.Logging
File(s): /home/runner/work/dotnet-logging/dotnet-logging/src/StateLogger.cs
Line coverage
98%
Covered lines: 56
Uncovered lines: 1
Coverable lines: 57
Total lines: 187
Line coverage: 98.2%
Branch coverage
91%
Covered branches: 53
Total branches: 58
Branch coverage: 91.3%
Method coverage
100%
Covered methods: 12
Fully covered methods: 11
Total methods: 12
Method coverage: 100%
Full method coverage: 91.6%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)50%2280%
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(...)91.66%3636100%
FormatMessageWithTraceId(...)100%22100%

File(s)

/home/runner/work/dotnet-logging/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)
 25    {
 5426        foreach (var config in configurations)
 27        {
 028            _loggers.Add(InternalLoggerFactory.Create(config));
 29        }
 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)
 38    {
 339        var (fp, mn) = ResolveCallerInfo(state);
 1240        foreach (var logger in _loggers)
 41        {
 342            logger.Trace(FormatMessageWithTraceId(message), fp, mn);
 43        }
 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)
 52    {
 453        var (fp, mn) = ResolveCallerInfo(state);
 1654        foreach (var logger in _loggers)
 55        {
 456            logger.Debug(FormatMessageWithTraceId(message), fp, mn);
 57        }
 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)
 66    {
 567        var (fp, mn) = ResolveCallerInfo(state);
 2268        foreach (var logger in _loggers)
 69        {
 670            logger.Info(FormatMessageWithTraceId(message), fp, mn);
 71        }
 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)
 80    {
 381        var (fp, mn) = ResolveCallerInfo(state);
 1282        foreach (var logger in _loggers)
 83        {
 384            logger.Warn(FormatMessageWithTraceId(message), fp, mn);
 85        }
 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)
 94    {
 395        var (fp, mn) = ResolveCallerInfo(state);
 1296        foreach (var logger in _loggers)
 97        {
 398            logger.Error(FormatMessageWithTraceId(message), fp, mn);
 99        }
 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)
 108    {
 3109        var (fp, mn) = ResolveCallerInfo(state);
 3110        var msg = FormatMessageWithTraceId(exception.ToString() ?? exception.Message);
 12111        foreach (var logger in _loggers)
 112        {
 3113            logger.Exception(msg, fp, mn);
 114        }
 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)
 123    {
 3124        var (fp, mn) = ResolveCallerInfo(state);
 12125        foreach (var logger in _loggers)
 126        {
 3127            logger.Critical(FormatMessageWithTraceId(message), fp, mn);
 128        }
 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)
 137    {
 3138        var (fp, mn) = ResolveCallerInfo(state);
 12139        foreach (var logger in _loggers)
 140        {
 3141            logger.Fatal(FormatMessageWithTraceId(message), fp, mn);
 142        }
 3143    }
 144
 145    private static (string filePath, string methodName) ResolveCallerInfo(object? state)
 146    {
 27147        string? filePath = null;
 27148        string? methodName = null;
 149
 27150        if (state is not IEnumerable<KeyValuePair<string, object>> pairs)
 151        {
 7152            return (filePath ?? "unknown", methodName ?? "unknown");
 153        }
 154
 101155        foreach (var (key, value) in pairs)
 156        {
 40157            if (value is null)
 158            {
 159                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)))
 165            {
 19166                filePath = value.ToString();
 167            }
 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)))
 173            {
 20174                methodName = value.ToString();
 175            }
 176
 58177            if (filePath != null && methodName != null) break;
 178        }
 179
 20180        return (filePath ?? "unknown", methodName ?? "unknown");
 181    }
 182
 183    private string FormatMessageWithTraceId(string message)
 184    {
 28185        return !string.IsNullOrEmpty(TraceId) ? $"[{nameof(TraceId)}] {TraceId} | {message}" : message;
 186    }
 187}