简体   繁体   English

使用 DependencyTracking 的控制台/WPF 应用程序中的应用程序洞察力

[英]Application insights in Console/WPF application with DependencyTracking

I have a application insights configuration I am trying to get working in a .NET 4.8 WPF application.我有一个应用程序洞察配置,我正在尝试在 .NET 4.8 WPF 应用程序中工作。 Everything seems to be transmitting fine (including the live metrics data) BUT unfortunately I cannot successfully get the system to transmit my SQL queries along with the Dependency information which are being executed by EntityFramework6.一切似乎都可以正常传输(包括实时指标数据),但不幸的是,我无法成功让系统传输我的 SQL 查询以及 EntityFramework6 正在执行的依赖信息。

I note that on the following link it makes reference to我注意到在以下链接中它引用了

For ASP.NET applications, full SQL query text is collected with the help of byte code instrumentation, which requires using the instrumentation engine or by using the Microsoft.Data.SqlClient NuGet package instead of the System.Data.SqlClient library. For ASP.NET applications, full SQL query text is collected with the help of byte code instrumentation, which requires using the instrumentation engine or by using the Microsoft.Data.SqlClient NuGet package instead of the System.Data.SqlClient library.

Obviously this is not possible for me (I dont think?) given that I am using EntityFramework (which depends on System.Data.SqlClient) but I have installed Microsoft.ApplicationInsights.Agent_** which I believe is the workaround for this issue as the link above suggests.显然这对我来说是不可能的(我不认为?),因为我正在使用 EntityFramework(这取决于 System.Data.SqlClient),但我已经安装了 Microsoft.ApplicationInsights.Agent_**,我认为这是解决此问题的方法上面的链接建议。

Further when I look at the data being provided in Azure I note that it is marked as rddf:2.17.0-32 which suggests that the agent is not working correctly.此外,当我查看 Azure 中提供的数据时,我注意到它被标记为 rddf:2.17.0-32 这表明代理无法正常工作。

在此处输入图像描述

My initialization code looks like this:我的初始化代码如下所示:

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

Can anyone provide any input on what I might be doing wrong?任何人都可以就我可能做错的事情提供任何意见吗?

While we all wait for a potential resolution from the insights team I thought I'd share my solution.当我们都在等待洞察团队的潜在解决方案时,我想我会分享我的解决方案。

Primarily my concern was to have more control about what data is provided when I tracked database operations.首先,我关心的是在跟踪数据库操作时更好地控制所提供的数据。 I was able to find a neat little feature in EntityFramework called DbInterception .我能够在 EntityFramework 中找到一个名为DbInterception的简洁小功能。

This singleton allows you to register interceptors which can track and profile queries provided to EntityFramework.这个 singleton 允许您注册拦截器,这些拦截器可以跟踪和分析提供给 EntityFramework 的查询。

The implementation ended up being as simple as this:实现最终就像这样简单:

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

Note that this registration is a singleton and if you want to exclude data you need to understand all your instances of DbContext will hit the interceptor.请注意,此注册是 singleton,如果您想排除数据,您需要了解所有 DbContext 实例将命中拦截器。

In my case I wanted to exclude SQLite queries as seen in the code.就我而言,我想排除代码中看到的 SQLite 查询。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM