'Microsoft.Extensions.Logging custom implementation, how to get the caller method name?
I'm in .NET 6, I implemented a custom ILogger<TService>
(of Microsoft.Extensions.Logging
).
Usually, when I implement a logger, I also get the caller method name with [CallerMemberName]
attribute, for example:
public void LogInformation(string message, [CallerMemberName] string callerName = null)
I really don't understand how to get the same [CallerMemberName]
with the ILogger<TService>
interface. I checked for EventId
, but it doesn't have that information.
// Dummy class, don't try this at home!
internal class CustomLogger<TService> : ILogger<TService>
{
public IDisposable BeginScope<TState>(TState state)
=> default;
public bool IsEnabled(LogLevel logLevel)
=> true;
public void Log<TState>(
LogLevel logLevel,
EventId eventId,
TState state,
Exception exception,
Func<TState, Exception, string> formatter)
{
// TODO How to get the caller name?
string callerName = "Log";
switch (logLevel)
{
case LogLevel.Trace:
case LogLevel.Debug:
case LogLevel.Information:
case LogLevel.Warning:
Console.WriteLine(callerName + ": " + formatter(state, exception));
break;
case LogLevel.Error:
case LogLevel.Critical:
Console.WriteLine(callerName + ": " + formatter(state, exception));
break;
}
}
}
Is there a bult-in way to get it without reflection
or other expensive methods?
Why I need to implement a custom ILogger<T>
?
- I use two external libraries which I don't control that want and
ILogger<T>
implementation (so I can't force them to call an extension method), - I need to store the logs by my own storage and there aren't any providers for what I need in this case
Why I need to add the CallerMemberName
?
- To enrich my logs. They are far more readable and informational with that information.
Solution 1:[1]
I really wish I could edit my own "comment", it was an answer converted to a comment, but, here it goes. From the answer I shared
public void Log()
{
var stackTrace = new System.Diagnostics.StackTrace(1); // skip one frame as this is the Log function frame
var name = stackTrace.GetFrame(0).GetMethod().Name;
}
or avoiding reflection
using (_logger.BeginScope("name of method"))
{
// log the stuff
}
credits to the original answer
Solution 2:[2]
you could add/overload the logging functions (extension methods) to the static LoggerExtensions class and in your Log function check for the beginning of the formatted message, split..
public static class LoggerExtensions
{
public static void LogCritical(this ILogger logger, string? message, [CallerMemberName] string callerMemberName = "")
{
logger.LogCritical("cmn_{message}_{caller}", message, callerMemberName);
}
public static void LogDebug(this ILogger logger, string? message, [CallerMemberName] string callerMemberName = "")
{
logger.LogDebug("cmn_{message}_{caller}", message, callerMemberName);
}
in Log<TState>
:
string message = formatter(state, exception);
string caller = "";
if (message.StartsWith("cmn"))
string[] messageSplit = message.Split(new char[] {'_'});
message = messageSplit[1];
caller = messageSplit[2];
}
(unfortunatelly you cannot directly access TState state
in Log<TState>
since it's internal, thus the split workaround)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | j.loucao.silva |
Solution 2 |