具有 DependencyTracking 的控制台/WPF 应用程序中的应用程序洞察

问题描述

我有一个应用程序洞察配置,我正在尝试在 .NET 4.8 WPF 应用程序中工作。一切似乎都在传输良好(包括实时指标数据),但不幸的是,我无法成功地让系统传输我的 sql 查询以及 EntityFramework6 正在执行的依赖关系信息。

我注意到在 following link 上它引用了

对于 ASP.NET 应用程序,完整的 sql 查询文本是通过 字节码检测的帮助,这需要使用 检测引擎或使用 Microsoft.Data.sqlClient NuGet 包而不是 System.Data.sqlClient 库。

显然这对我来说是不可能的(我不认为?),因为我正在使用 EntityFramework(这取决于 System.Data.sqlClient)但我已经安装了 Microsoft.ApplicationInsights.Agent_**,我认为这是解决方法这个问题正如上面的链接所暗示的那样。

此外,当我查看 Azure 中提供的数据时,我注意到它被标记为 rddf:2.17.0-32,这表明代理工作不正常。

enter image description here

我的初始化代码如下所示:

public static TelemetryConfiguration CreateConfig(string instrumentationKey,string authenticationApiKey)
{
    var config = new TelemetryConfiguration()
    {
        ConnectionString = $"InstrumentationKey={instrumentationKey};IngestionEndpoint=https://australiaeast-0.in.applicationinsights.azure.com/",TelemetryChannel = new ServerTelemetryChannel()
        {
            DeveloperMode = true
        },};

    var dependencyTrackingModule = new DependencyTrackingTelemetryModule()
    {
        EnablesqlCommandTextInstrumentation = true
    };

    // prevent Correlation Id to be sent to certain endpoints. You may add other domains as needed.
    dependencyTrackingModule.ExcludeComponentCorrelationHttpHeadersOnDomains.Add("core.windows.net");

    // enable kNown dependency tracking,note that in future versions,we will extend this list. 
    dependencyTrackingModule.IncludeDiagnosticSourceActivities.Add("Microsoft.Azure.ServiceBus");
    dependencyTrackingModule.IncludeDiagnosticSourceActivities.Add("Microsoft.Azure.EventHubs");

    // initialize the module
    dependencyTrackingModule.Initialize(config);

    QuickpulseTelemetryProcessor quickpulseProcessor = null;
    config.DefaultTelemetrySink.TelemetryProcessorChainBuilder
        .Use((next) =>
        {
            quickpulseProcessor = new QuickpulseTelemetryProcessor(next);
            return quickpulseProcessor;
        })
        .Build();

    var quickpulseModule = new QuickpulseTelemetryModule()
    {
        AuthenticationApiKey = authenticationApiKey
    };

    quickpulseModule.Initialize(config);
    quickpulseModule.RegisterTelemetryProcessor(quickpulseProcessor);

    config.TelemetryInitializers.Add(new HttpDependenciesParsingTelemetryInitializer());
    config.TelemetryInitializers.Add(new BuildInfoConfigComponentVersionTelemetryInitializer());

    return config;
}

任何人都可以就我可能做错的事情提供任何意见吗?

解决方法

虽然我们都在等待洞察团队的潜在解决方案,但我想我会分享我的解决方案。

我主要关心的是在跟踪数据库操作时对提供的数据有更多的控制。我能够在 EntityFramework 中找到一个名为 DbInterception 的简洁小功能。

此单例允许您注册拦截器,这些拦截器可以跟踪和分析提供给 EntityFramework 的查询。

最终实现就这么简单:

internal class InsightsOperation 
{
    public InsightsOperation(DbCommand command,Stopwatch stopwatch)
    {
        this.Command = command;
        this.Stopwatch = stopwatch;
    }

    public DbCommand Command { get; }
    public Stopwatch Stopwatch { get; }
    public DateTime StartTime { get; } = DateTime.UtcNow;
}

public class AppInsightsInterceptor : IDbCommandInterceptor
{

    private ConcurrentDictionary<Guid,InsightsOperation> _pendingOperations = new ConcurrentDictionary<Guid,InsightsOperation>();
    private ITelemetryManager _telemetryManager;

    public AppInsightsInterceptor(ITelemetryManager telemetryManager)
    {
        this._telemetryManager = telemetryManager ?? throw new ArgumentNullException(nameof(telemetryManager));
    }

    private void StartTimingOperation<T>(DbCommand command,DbCommandInterceptionContext<T> interceptionContext)
    {
        if (!(command is SQLiteCommand))
        {
            var id = Guid.NewGuid();
            var stopwatch = Stopwatch.StartNew();

            interceptionContext.SetUserState(nameof(AppInsightsInterceptor),id);
            this._pendingOperations.TryAdd(id,new InsightsOperation(command,stopwatch));
        }
    }

    private void StopTimingOperation<T>(DbCommand command,DbCommandInterceptionContext<T> interceptionContext)
    {
        if (!(command is SQLiteCommand))
        {
            var id = (Guid)interceptionContext.FindUserState(nameof(AppInsightsInterceptor));
            if (this._pendingOperations.TryRemove(id,out InsightsOperation operation))
            {
                operation.Stopwatch.Stop();
                this._telemetryManager.TrackDependency(command.CommandType.ToString(),"SQL",command.CommandText,new DateTimeOffset(operation.StartTime),operation.Stopwatch.Elapsed,interceptionContext.Exception == null);
            }
        }
    }

    public void NonQueryExecuted(DbCommand command,DbCommandInterceptionContext<int> interceptionContext)
    {
        this.StopTimingOperation(command,interceptionContext);
    }

    public void NonQueryExecuting(DbCommand command,DbCommandInterceptionContext<int> interceptionContext)
    {
        this.StartTimingOperation(command,interceptionContext);            
    }

    public void ReaderExecuted(DbCommand command,DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        this.StopTimingOperation(command,interceptionContext);
    }

    public void ReaderExecuting(DbCommand command,DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        
        this.StartTimingOperation(command,interceptionContext);
            
    }

    public void ScalarExecuted(DbCommand command,DbCommandInterceptionContext<object> interceptionContext)
    {
        this.StopTimingOperation(command,interceptionContext);
    }

    public void ScalarExecuting(DbCommand command,DbCommandInterceptionContext<object> interceptionContext)
    {
        this.StartTimingOperation(command,interceptionContext);
    }
}

请注意,此注册是单例,如果您想排除数据,您需要了解所有 DbContext 实例都将命中拦截器。

就我而言,我想排除代码中看到的 SQLite 查询。