4

I want to save Activity.Current?.Id ?? HttpContext.TraceIdentifier into database, because that is Request Id which user see in default error view. But how ? HttpContext is not available in startup.cs and i tried access HttpContext in LayoutRenderer not successfully.

Error method in HomeController

public IActionResult Error()
{
    var model = new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier };

    return View(model);
}

I tried LayoutRenderer

namespace Copacking.Web.Utils
{
    [LayoutRenderer("requestid")]
    public class NLogRequestIdLayoutRenderer : LayoutRenderer
    {
        protected override void Append(StringBuilder builder, LogEventInfo logEvent)
        {
            builder.Append(Activity.Current?.Id ?? HttpContext.TraceIdentifier);
        }
    }
}

but I am getting an error with HttpContext, because object reference is required.

How can i solve it ? In Nlog.config file ${aspnet-traceidentifier} is working but ${activityid} variable is empty :/

Muflix
  • 6,192
  • 17
  • 77
  • 153

3 Answers3

5

You can do the following with https://www.nuget.org/packages/NLog.Web.AspNetCore:

layout="${activityid:whenEmpty=${mdlc:item=RequestId:whenEmpty=${aspnet-TraceIdentifier}}}"

Remember to include the following in NLog.config:

<extensions>
  <add assembly="NLog.Web.AspNetCore"/>
</extensions>
Rolf Kristensen
  • 17,785
  • 1
  • 51
  • 70
4

How can i solve it ? In Nlog.config file ${aspnet-traceidentifier} is working but ${activityid} variable is empty :/

As per NLog wiki ${Activity} takes the value from Trace.CorrelationManager.ActivityId. You try assigning a value at the request start.

if(System.Diagnostics.Trace.CorrelationManager.ActivityId.Equals(Guid.Empty))
   System.Diagnostics.Trace.CorrelationManager.ActivityId = Guid.NewGuid();
Jawahar
  • 117
  • 7
3

I'm not directly familiar with NLog, so forgive me if I'm missing something here, but in a truly abstracted logging setup, you shouldn't really have any hard NLog depedency, anyhow. Ideally, you should be using something like Microsoft.Extensions.Logging, and simply plugging NLog into that as the provider.

Then, from the controller perspective, you simply inject your logger, and log directly there:

public class ErrorController : Controller
{
    private readonly ILoggerFactory _loggerFactory;

    public ErrorController(ILoggerFactory loggerFactory)
    {
        _loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
    }

    public IActionResult Error()
    {
        var feature = HttpContext.Features.Get<IExceptionHandlerFeature>();
        var logger = _loggerFactory.CreateLogger(feature.Error.TargetSite.DeclaringType);
        logger.LogError(feature.Error, "{RequestId} {ErrorMessage}", new
        {
            RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier,
            ErrorMessage = feature.Error.Message
         });

         var model = new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier };

         return View(model);
    }
Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • You are completely right I am just thinking about two approaches. One is log only unhandled exceptions in Error method in HomeController (All exceptions are redirected there) If I use Nlog directly i can setup additional variables. But if I register Nlog as Ilogger provider now i dont need call log insertion because it is called automatic in the case of unhandled error. But in the automatic way (NLog as a provider) I dont know how to setup RequestId. I will try the IHttpContextAccessor way into LayoutRenderer or after that i will try different log provider. – Muflix Jul 09 '18 at 19:40