c# log4net async-await methodbase

c# - MoveNext en lugar del nombre del método/tarea real



log4net async-await (5)

Escribí un envoltorio simple alrededor de 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); } }

En el código que está haciendo el registro, simplemente haga:

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

Por supuesto, si desea hacer cosas como Información, Depuración, etc., simplemente puede agregarlo a la clase contenedora.

NOTA
esto utiliza el c # 5.0 [CallerMemberName]

Usando log4net declarado como:

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

En un método o tarea asíncrona, como esta:

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

CheckSomething MoveNext lugar de CheckSomething . ¿Alguna idea de cómo hacer que se registre un nombre de método real?


Gracias a la respuesta de Jacek Gorgoń, aquí está la utilidad que encontré. Tiene un par de mejoras, pero aún tiene un largo camino por recorrer para trabajar bien con métodos anónimos o lambda.

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

Aquí hay un ejemplo de uso:

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


Todos los métodos async se reescriben en una máquina de estado para satisfacer los valores potenciales de await dentro del método. El último método en el que vive el código es el método MoveNext , que es lo que log4net informa.

Realmente no hay una buena forma en tiempo de ejecución para hacer la transición de MoveNext al método real en el que se escribió originalmente el código. Están un tanto desconectados a nivel de metadatos. Es posible que tenga que recurrir al registro del nombre directamente.


Usa esto, funciona muy bien ...

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.... }


Corto : dado el método MoveNext() , intente esto:

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

Largo (descargo de responsabilidad)

No uses esto en producción. Se basa en el comportamiento del compilador, que probablemente cambie en una versión futura sin previo aviso. Se hacen las siguientes suposiciones sobre el compilador:

  1. El método asíncrono en ejecución real se genera dentro de un tipo generado.
  2. El tipo generado es un tipo anidado del tipo original que contiene el método original escrito a mano.
  3. El método original obtiene un atributo generado por el compilador AsyncStateMachine con el tipo generado incluido en él.

Funciona en mi código, donde lo uso para el análisis de código en tiempo de ejecución solo durante la depuración / pruebas. Una vez más, por favor, no lo use en el código de producción .