Log UserName and IP with Custom Properties in Application Insight .Net Core 2.1

断了今生、忘了曾经 提交于 2021-02-07 23:02:51

问题


We are running an intranet Application on .Net Core 2.0. Application insight is very helpfull to catch exceptions. So when the User comes up to us for support we would like to find his request that caused problems in application insight. I added an ClientIpHeaderTelemetryInitializer like this:

public class CustomTelemetry : ClientIpHeaderTelemetryInitializer
    {
        private readonly IHttpContextAccessor _httpContextAccessor ;

        public CustomTelemetry(IHttpContextAccessor httpContextAccessor) : base(httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        /// <summary>
        /// Implements initialization logic.
        /// </summary>
        /// <param name="platformContext">Http context.</param>
        /// <param name="requestTelemetry">Request telemetry object associated with the current request.</param>
        /// <param name="telemetry">Telemetry item to initialize.</param>
        protected override void OnInitializeTelemetry(HttpContext platformContext, RequestTelemetry requestTelemetry, ITelemetry telemetry)
        {

            requestTelemetry.Properties.Add("UserName", _httpContextAccessor.HttpContext.User.Identity.Name);
            if (string.IsNullOrEmpty(telemetry.Context.Location.Ip))
            {
                LocationContext location = requestTelemetry.Context.Location;
                telemetry.Context.Location.Ip = location.Ip;
                requestTelemetry.Properties.Add("InternalIP", location.Ip);
            }
        }
    }

The Initalizer is registered at startup like this:

services.AddSingleton<ITelemetryInitializer, CustomTelemetry>();  

When I look at the requests Custom Data still turns up empty.
Did I register it wrong? I found the exact same line to add the service in the Integration Tests of Application Insights (although commented out...)
Has anyone an Idea whats wrong?


回答1:


I finally got it working for my purposes.

public class CustomTelemetry : ClientIpHeaderTelemetryInitializer
    {
        private readonly IHttpContextAccessor _httpContextAccessor ;

        public CustomTelemetry(IHttpContextAccessor httpContextAccessor) : base(httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        /// <summary>
        /// Implements initialization logic.
        /// </summary>
        /// <param name="platformContext">Http context.</param>
        /// <param name="requestTelemetry">Request telemetry object associated with the current request.</param>
        /// <param name="telemetry">Telemetry item to initialize.</param>
        protected override void OnInitializeTelemetry(HttpContext platformContext, RequestTelemetry requestTelemetry, ITelemetry telemetry)
        {
            var userName = _httpContextAccessor.HttpContext?.User?.Identity?.Name; // Only set when request failed...
            var ip = _httpContextAccessor.HttpContext?.Connection?.RemoteIpAddress?.ToString();
            if (ip != null) telemetry.Context.GlobalProperties.TryAdd("InternalIP", ip);
            if(userName != null) requestTelemetry.Properties.Add("UserName", userName);
        }
     }

(Note: ClientIpHeaderTelemetryInitializer is part of AppInsights)

Important here is to get everything from the HttpContext, checking if it is null and adding custom properties. The built in properties for IP can get overwritten otherwise. Migrosoft GDPR Blogpost

In the Startup add this to ConfigureService

services.AddSingleton<ITelemetryInitializer, CustomTelemetry>();

Make sure to add the ContextAccessor beforehand so it can be injected:

services.AddHttpContextAccessor();

In Configure add this at the beginning:

app.UseForwardedHeaders(new ForwardedHeadersOptions{ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto});

This is very important to optain the IP Adress when using reverse proxy like IIS. Otherwise you will always receive localhost. UseForwardedHeaders() without options just does nothing! (Also you will need a test setup with a remote server)

Getting the Username just seems to work when the Request fails (tested with 500 Internal Server Error). Otherwise the HttpContextAccessor doesn't populate the User object. Could be a 2.1 thing, quite annoying maybe someone finds a way to get it for every request.

In the end your information should arrive at ApplicationInsights and look like this:




回答2:


First, you need to add application insights to your asp.net core project via menu option in visual studio:

Second, in your CustomTelemetry class, you'd better set a breakpoint to make sure it can be hit when code is running.

Third, in your CustomTelemetry class, please do some logic when UserName and InternalIP is null or empty. If these values are null or empty, they will not be added.

My test code as below:

CustomTelemetry class:

public class CustomTelemetry: ITelemetryInitializer
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public CustomTelemetry(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public void Initialize(ITelemetry telemetry)
    {
        var requestTelemetry = telemetry as RequestTelemetry;
        if (requestTelemetry == null) return;

        if (!requestTelemetry.Context.Properties.ContainsKey("UserName"))
        {
            //if UserName is null or empty, add a default value for it
            if (string.IsNullOrEmpty(_httpContextAccessor.HttpContext.User.Identity.Name))
            {
                requestTelemetry.Context.Properties.Add("UserName", "NA");
            }
            else
            {
                requestTelemetry.Context.Properties.Add("UserName", _httpContextAccessor.HttpContext.User.Identity.Name);
            }

        }
        if (!requestTelemetry.Context.Properties.ContainsKey("InternalIP"))
        {
            //update
            if (!string.IsNullOrEmpty(requestTelemetry.Context.Location.Ip))
            {
                requestTelemetry.Context.Properties.Add("InternalIP", requestTelemetry.Context.Location.Ip);                   
            }
        }
    }
}

Then register in Startup class:

public void ConfigureServices(IServiceCollection services)
{
   services.AddMvc();
   services.AddSingleton<ITelemetryInitializer, CustomTelemetry>();
   services.AddApplicationInsightsTelemetry();
}

Test result:

Since I don't have your ClientIpHeaderTelemetryInitializer class, just write the above test code. If you need more help, please share that class.



来源:https://stackoverflow.com/questions/52854319/log-username-and-ip-with-custom-properties-in-application-insight-net-core-2-1

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!