Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

$Callsite always shows MoveNext for c# 5 async/awaited methods #255

Closed
DavidDWill opened this issue Aug 26, 2013 · 14 comments
Closed

$Callsite always shows MoveNext for c# 5 async/awaited methods #255

DavidDWill opened this issue Aug 26, 2013 · 14 comments

Comments

@DavidDWill
Copy link

If I have methods that are annotated with the async keyword and called as an awaited method, the callsite method name always returns MoveNext.

@ghost
Copy link

ghost commented Aug 29, 2013

Thanks for the bug report, I'll look into this soon

@ghost
Copy link

ghost commented Sep 6, 2013

As described multiple places, such as:

There are currently no good way to get a clear stacktrace from an async method. So this issue will be postponed, at least till the next version

@304NotModified
Copy link
Member

We should document this behavior and close this issue afterwards

@304NotModified 304NotModified removed the bug Bug report / Bug fix label Jan 25, 2015
@304NotModified
Copy link
Member

note added to the wiki.

https://github.com/NLog/NLog/wiki/Callsite-layout-renderer

thanks for the report.

@pinchegera
Copy link

I use the following extension methods in my code and it always seems to work for me.

internal static class DiagnosticExtensions
{
    /// <summary>
    /// Gets the fully qualified name of the container class.
    /// </summary>
    /// <param name="type">The type.</param>
    /// <returns></returns>
    public static string GetContainerClassName(this Type type)
    {
        var stackFrames = new StackTrace().GetFrames();
        if (stackFrames == null)
            return null;

        var thisType = typeof(DiagnosticExtensions);

        return (stackFrames.Select(f => f.GetMethod().DeclaringType)
            .Where(delaringType => type != delaringType && thisType != delaringType)
            .Select(delaringType => delaringType?.FullName)).FirstOrDefault();
    }

    /// <summary>
    /// Gets the fully qualified name of the container class.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="t">The generic class.</param>
    /// <returns></returns>
    public static string GetContainerClassName<T>(this T t)
        where T : class
    {
        return t.GetType().GetContainerClassName();
    }
}

@304NotModified
Copy link
Member

Cool! Thanks! We will try it :)

@Soruk
Copy link

Soruk commented Feb 17, 2016

I think that using StackTrace will have a serious impact on performance (when I removed the use of StackTrace and GetFrames; my code run 30 seconds instead of 2 minutes).

I propose to use these methods:
public static string GetMemberName([CallerMemberName] string memberName = "") { return memberName; }
and
public static int GetSourceLineNumber([CallerLineNumber] int sourceLineNumber = 0) { return sourceLineNumber; }
See more details here

@304NotModified
Copy link
Member

Agree, stacktrace uses some performance. But this is for ages and we had no performance complaints.

my code run 30 seconds instead of 2 minutes

Which test is that?

I propose to use these methods:
public static string GetMemberName([CallerMemberName] string memberName = "") { return memberName; }
and
public static int GetSourceLineNumber([CallerLineNumber] int sourceLineNumber = 0) { return sourceLineNumber; }

We like it, but that's not binary compatible AND most of the time those are not the member/linenumbers you needed. (e.g. there is proxy between it)

@Soruk
Copy link

Soruk commented Feb 17, 2016

I am working on module that must be fast (a loop of 5000 elements that has multiple loops inside, the code is very complex).
Lately, we implemented custom logger by extending Logger from NLog (to add error code and other informations stored in LogEventInfo properties), and we used StackTrace to get current method name. And my test with the big loop took 2 minutes to complete, but when I removed the code that was using StackTrace, it runs now for 30 secondes.

The 'GetMemberName' methods returns actually the name of parent method. We used it to bypass the "MoveNext" problem but also to have human readable method when a cod is protected by obfuscation.

@304NotModified
Copy link
Member

Nice. We like to change it, if we could do it optional / backwards-compatible.

So if you have ideas on that, let us know :)

@Soruk
Copy link

Soruk commented Feb 25, 2016

Maybe, it would be easy to use only these methods when targeting .Net 4.5 or above (using preporcesisng directives), and lower old code when targeting old frameworks.
Or add new layout render ${methodName} available only when targeting .Net 4.5 or above.

@304NotModified
Copy link
Member

yes, was thinking about that. But then the logger methods are binary incompatible between frameworks. That's also not nice - but maybe we have to live with that.

If you change your framework (.e.g net4 => net45), you need to include the other nlog.dll and it needs a recompile of your program after it.

@304NotModified
Copy link
Member

PS: #532

@304NotModified
Copy link
Member

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants