在 Application Insight .Net Core 2.1 中使用自定义属性记录用户名和 IP

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

我们是 运行 .Net Core 2.0 上的 Intranet 应用程序。应用程序洞察力非常有助于捕获异常。因此,当用户向我们寻求支持时,我们希望找到他的请求导致应用程序洞察出现问题。我添加了一个 ClientIpHeaderTelemetryInitializer,如下所示:

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

Initalizer 在启动时注册如下:

services.AddSingleton<ITelemetryInitializer, CustomTelemetry>();  

当我查看自定义数据请求时,仍然显示为空。
我是不是注册错了?我在 Application Insights 的集成测试中找到了添加服务的完全相同的行(尽管被注释掉了...)
有没有人知道哪里出了问题?

首先,您需要通过 visual studio 中的菜单选项将应用程序洞察添加到您的 asp.net 核心项目:

其次,在你的CustomTelemetryclass中,你最好设置一个断点以确保在代码为运行.

时可以命中它。

第三,在你的 CustomTelemetry class 中,请在 UserNameInternalIP 为 null 或空时做一些逻辑。如果这些值为 null 或为空,则不会添加它们。

我的测试代码如下:

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

然后在Startup注册 class:

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

测试结果:

因为我没有你的ClientIpHeaderTelemetryInitializerclass,就写上面的测试代码吧。如果您需要更多帮助,请分享 class.

我终于让它为我的目的工作了。

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

(注意:ClientIpHeaderTelemetryInitializer 是 AppInsights 的一部分)

此处重要的是从 HttpContext 获取所有内容,检查它是否为 null 并添加自定义属性。否则,IP 的内置属性可能会被覆盖。 Migrosoft GDPR Blogpost

Startup 中将其添加到 ConfigureService

services.AddSingleton<ITelemetryInitializer, CustomTelemetry>();

确保事先添加 ContextAccessor 以便可以注入:

services.AddHttpContextAccessor();

在Configure的开头加上这个:

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

在使用 反向代理IIS 时,获取 IP 地址 非常重要.否则,您将始终收到本地主机。没有选项的 UseForwardedHeaders() 什么都不做! (您还需要使用远程服务器进行测试设置)

获取 用户名 似乎在请求失败时有效(通过 500 内部服务器错误测试)。否则 HttpContextAccessor 不会填充用户对象。可能是 2.1 的东西,很烦人,也许有人找到了一种方法来为每个请求获取它。

最后,您的信息应该到达 ApplicationInsights,如下所示: