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);