Application Insights add username to telemetry

4

I'm trying to log the usernames for users in application insights when they are doing requests.

I've been trying to do it this way as:

 public class AppInsightsInitializer : ClientIpHeaderTelemetryInitializer
    {
        private readonly IHttpContextAccessor _httpContextAccessor;

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

        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 (userName != null) requestTelemetry.Context.User.AuthenticatedUserId= userName;
        }
    }

After injecting and registering the telemtry in Startup.cs:

 services.AddApplicationInsightsTelemetry(instrumentKey);
 services.AddSingleton<ITelemetryInitializer, AppInsights.AppInsightsInitializer>();

But this one results in a System.ObjectDisposedException: 'Safe handle has been closed

System.ObjectDisposedException
  HResult=0x80131622
  Message=Safe handle has been closed
  Source=mscorlib
  StackTrace:
   at System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean& success)
   at System.StubHelpers.StubHelpers.SafeHandleAddRef(SafeHandle pHandle, Boolean& success)
   at Microsoft.Win32.Win32Native.GetTokenInformation(SafeAccessTokenHandle TokenHandle, UInt32 TokenInformationClass, SafeLocalAllocHandle TokenInformation, UInt32 TokenInformationLength, UInt32& ReturnLength)
   at System.Security.Principal.WindowsIdentity.GetTokenInformation(SafeAccessTokenHandle tokenHandle, TokenInformationClass tokenInformationClass)
   at System.Security.Principal.WindowsIdentity.get_User()
   at System.Security.Principal.WindowsIdentity.GetName()
   at System.Security.Principal.WindowsIdentity.get_Name()
   at Webeco.Web.AppInsights.AppInsightsInitializer.OnInitializeTelemetry(HttpContext platformContext, RequestTelemetry requestTelemetry, ITelemetry telemetry) in C:\Users\SESEGU\Documents\Projects\AppInsights\AppInsightsInitializer.cs:line 24
   at Microsoft.ApplicationInsights.AspNetCore.TelemetryInitializers.TelemetryInitializerBase.Initialize(ITelemetry telemetry)
   at Microsoft.ApplicationInsights.TelemetryClient.Initialize(ITelemetry telemetry)

Then I tried the below code:

 public class AppInsightsInitializer : ITelemetryInitializer
    {
        public void Initialize(ITelemetry telemetry)
        {
            var identity = WindowsIdentity.GetCurrent();
            if (identity != null)
            {
                var name = new WindowsPrincipal(identity);
                telemetry.Context.User.AuthenticatedUserId = name.Identity.Name;
            }
        }
    }

This works well on a localmachine. But when I try it in dev environment it only logs the server name instead of the user name.

So I'm thinking that my first solution is the correct way to go. However I can't get past it crashing with the Safe handle has been closed exception.

Any help in getting past this?

c#
asp.net
azure-application-insights
asked on Stack Overflow Dec 13, 2019 by Gurkmeja101

1 Answer

2

After looking around a bit it looks like this might solve your problem

    public class AuthenticatedUserIdTelemetryInitializer : ITelemetryInitializer
    {
        IHttpContextAccessor httpContextAccessor;

        public AuthenticatedUserIdTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
        {
            this.httpContextAccessor = httpContextAccessor;
        }

        public void Initialize(ITelemetry telemetry)
        {
            if (this.httpContextAccessor?.HttpContext?.User?.Identity?.IsAuthenticated == true)
                telemetry.Context.User.AuthenticatedUserId = this.httpContextAccessor.HttpContext.User.Identity.Name;
        }
    }

It is really a combination of your two examples. I believe that the difference is in using Initialize method instead of the overridden OnInitializeTelemetry method. It might be that your httpContextAccessor is still alive in the Initialize method, while it is already disposed in the overridden one. Not sure what is the motivation to inherit from ClientIpHeaderTelemetryInitializer and if it is relevant.

Code is copied from here.

answered on Stack Overflow Dec 13, 2019 by Nesaje

User contributions licensed under CC BY-SA 3.0