MoveNext instead of the actual method / task name

Using log4net declared as:

private readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType()); 

In an asynchronous method or task like this:

 public async void CheckSomething() { log.Info(null); //.... } 

logs CheckSomething instead of CheckSomething . Any idea how to get it to register the name of the actual method?

+19
c # async-await log4net
Mar 23 '14 at 23:03
source share
6 answers

All async methods are written to the state machine to satisfy potential await values ​​inside the method. The final method in which the code runs is the MoveNext method, which is a log4net report.

In runtime, there is no good way to go from MoveNext to the actual method in which the code was originally written. They are somewhat disabled at the metadata level. You just need to resort to registering a name directly

+22
Mar 24 '14 at 1:29
source share

Short : Given the MoveNext() method, try the following:

 private static MethodBase GetRealMethodFromAsyncMethod(MethodBase asyncMethod) { var generatedType = asyncMethod.DeclaringType; var originalType = generatedType.DeclaringType; var matchingMethods = from methodInfo in originalType.GetMethods() let attr = methodInfo.GetCustomAttribute<AsyncStateMachineAttribute>() where attr != null && attr.StateMachineType == generatedType select methodInfo; // If this throws, the async method scanning failed. var foundMethod = matchingMethods.Single(); return foundMethod; } 

Long (disclaimer)

Do not use this in the manufacturing process. It relies on compiler behavior, which is likely to change in a future version without notice. The following assumptions about the compiler are made:

  • The actual current async method is generated inside the generated type.
  • A generated type is a nested type of the source type containing the original manual method.
  • The original method receives the AsyncStateMachine attribute created by the compiler, with the generated type provided in it.

It works in my code where I use it to parse runtime code during debugging / tests. Again, please do not use it in production code .

+8
Feb 20 '15 at 16:01
source share

I wrote a simple wrapper around log4net.

 public class Logger { private ILog _Log { get; set; } public Logger(Type declaringType) { _Log = LogManager.GetLogger(declaringType); } public void Error(Exception exception, [CallerMemberName] string callerMemberName = "") { _Log.Error(callerMemberName, exception); } } 

In the code that does the logging, simply do:

 private Logger Log = new Logger(MethodBase.GetCurrentMethod().DeclaringType); 

Of course, if you want to do things like Info, Debug, etc., you can just add it to the shell class.

Note
it uses C # 5.0 [CallerMemberName]

+1
May 12 '15 at
source share

Thanks to Jacek Gorgon’s answer, here is the utility that I came up with. It has several improvements, but it still has a long way to go to work well with anonymous or lambda methods.

 static string GetMethodContextName() { var name = new StackTrace().GetFrame(1).GetMethod().GetMethodContextName(); } static string GetMethodContextName(this MethodBase method) { if (method.DeclaringType.GetInterfaces().Any(i => i == typeof(IAsyncStateMachine))) { var generatedType = method.DeclaringType; var originalType = generatedType.DeclaringType; var foundMethod = originalType.GetMethods(Instance | Static | Public | NonPublic | DeclaredOnly) .Single(m => m.GetCustomAttribute<AsyncStateMachineAttribute>()?.StateMachineType == generatedType); return foundMethod.DeclaringType.Name + "." + foundMethod.Name; } else { return method.DeclaringType.Name + "." + method.Name; } } 

Here is a usage example:

 class Program { static void Main(string[] args) { // outputs Program.Main Console.WriteLine(GetMethodContextName()); Test().Wait(); } static async Task Test() { // outputs Program.Test Console.WriteLine(GetMethodContextName()); await Task.CompletedTask; } } 
+1
Feb 13 '18 at 1:40
source share

Use this, works great ...

 public void Log(Microsoft.Extensions.Logging.LogLevel level, string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0) { //do your logging here.... } 
+1
Sep 06 '18 at 19:53
source share

With an extension method that simply returns the name of the caller member for MethodBase.

 public static class MemberBaseExtension { public static string GetDeclaringName(this MethodBase methodBase, [CallerMemberName] string memberName = "") { return memberName; } } 
0
May 12 '19 at 20:47
source share



All Articles