弹性APM显示在.Net Core API端点上执行的SQL查询的总数

问题描述

当前已使用以下命令设置了弹性Apm:app.UseAllElasticApm(Configuration);,它可以正常工作。我一直在试图找到一种方法来准确记录通过Entity Framework为每个事务运行的SQL查询数量

理想情况下,在Kibana中查看Apm数据时,元数据标签可能只包含EntityFramework.ExecutedsqlQueriesCount

当前在.Net Core 2.2.3上

解决方法

您可以使用的一件事是Filter API

有了它,您就可以在将所有事务和跨度发送到APM服务器之前对其进行访问。

对于给定的交易,您无法遍历所有范围,因此您需要进行一些调整-为此,我在示例中使用了Dictionary

var numberOfSqlQueries = new Dictionary<string,int>();

Elastic.Apm.Agent.AddFilter((ITransaction transaction) =>
{
    if (numberOfSqlQueries.ContainsKey(transaction.Id))
    {
        // We make an assumption here: we assume that all SQL requests on a given transaction end before the transaction ends
        // this in practice means that you don't do any "fire and forget" type of query. If you do,you need to make sure
        // that the numberOfSqlQueries does not leak.
        transaction.Labels["NumberOfSqlQueries"] = numberOfSqlQueries[transaction.Id].ToString();
        numberOfSqlQueries.Remove(transaction.Id);
    }

    return transaction;
});

Elastic.Apm.Agent.AddFilter((ISpan span) =>
{
    // you can't relly filter whether if it's done by EF Core,or another database library
    // but you have all sorts of other info like db instance,also span.subtype and span.action could be helpful to filter properly
    if (span.Context.Db != null && span.Context.Db.Instance == "MyDbInstance")
    {
        if (numberOfSqlQueries.ContainsKey(span.TransactionId))
            numberOfSqlQueries[span.TransactionId]++;
        else
            numberOfSqlQueries[span.TransactionId] = 1;
    }

    return span;
});

这里的事物:

  • 我假设您不会执行“即兴即忘”类型的查询,如果您这样做,则需要处理那些额外的问题
  • 该计数并非真正针对EF Core查询,但您拥有诸如数据库名称,数据库类型(mssql等)之类的信息-希望以此为基础,您将能够过滤所需的查询。
  • 使用transaction.Labels["NumberOfSqlQueries"],我们将标签添加到给定的交易中,您将可以在Kibana上的交易中看到此数据。