Here is the CallerContext and ILoggerExtension class
using System.Runtime.CompilerServices; /// <summary> /// A class to record the context of a method call. /// Records the member name, file and line number of where the method call was made. /// </summary> public record CallerContext { public CallerContext( [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { MemberName = memberName; FilePath = sourceFilePath; LineNumber = sourceLineNumber; } /// <summary> /// Member where the call was made /// </summary> public string MemberName { get; init; } /// <summary> /// File where the call was made /// </summary> public string FilePath { get; init; } /// <summary> /// Line number in the file where the call was made /// </summary> public int LineNumber { get; init; } } /// <summary> /// To get the code context using caller member attributes /// </summary> public static class Code { public static CallerContext Context( [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { return new CallerContext(memberName, sourceFilePath, sourceLineNumber); } } /// <summary> /// ILogger extensions /// </summary> public static class ILoggerExt { /// <summary> /// Log something but with extra Caller context information <seealso cref="CallerContext"/> /// </summary> /// <param name="logger">ILogger being invoked</param> /// <param name="logLevel">Level of the logging</param> /// <param name="context">The caller context <see cref="CallerContext"/></param> /// <param name="message">The message to log</param> /// <param name="args">The message parameters to log.</param> public static void Log(this ILogger logger, LogLevel logLevel, CallerContext context, string message, params object[] args) { Debug.Assert(logger != null, "trying to use a null logger to log something"); var enhancedMessage = "{@CallerContext} " + (message ?? ""); Debug.Assert(args != null, "args cannot be null"); object[] newArgs = new object[args.Length + 1]; newArgs[0] = context; // Prepend the context argument Array.Copy(args, sourceIndex: 0, newArgs, destinationIndex:1, args.Length); // add the other arguments logger.Log(logLevel, enhancedMessage, newArgs.ToArray()); } }
Example Usage
ILogger logger = ... logger.Log(new CallerContext(), LogLevel.Info, "Message with {@parameters} goes here", parameters); // OR logger.Log(Code.Context(), LogLevel.Info, "Message with {@parameters} goes here", parameters);