使用New Relic对独立的.NET桌面应用程序进行性能监控

3
我想知道是否有一种方法可以监控一个独立的.NET桌面应用程序的性能?(例如,foobar.exe)
这是一个客户端应用程序,最终可能会与Web服务或数据库交互,在涉及到数据库连接的情况下,我希望能够:
1. 监视应用程序的性能(例如,花费的时间或调用的方法数量等); 2. 监视所执行的SQL查询/存储过程。
感谢您的任何帮助。
谢谢,
1个回答

5

我在New Relic工作。

只要满足以下要求,就可以监控非IIS应用程序的性能:

  • 必须启用“Instrument All .NET Applications”功能

  • 需要为.exe配置App.config和/或newrelic.config

您可以在我们的文档网站上阅读有关这些要求的更多信息: https://docs.newrelic.com/docs/dotnet/instrumenting-custom-applications

您可能需要使用我们的.NET代理API来收集自定义指标。方法RecordMetric、RecordResponseTimeMetric和IncrementCounter专门用于非Web应用程序。 我们的.NET代理API文档位于此处:https://docs.newrelic.com/docs/dotnet/net-agent-api

您还可以设置自定义事务以跟踪非Web事务。通常,我们可以跟踪使用HttpObjects的函数,但以下是代理版本2.24.218.0中实现的新功能。 对于没有事务上下文的非Web应用程序和异步调用,可以使用以下功能创建事务,代理通常无法执行此操作。这是通过自定义插装文件进行的手动过程。

在C:\ProgramData\New Relic.NET Agent\Extensions中创建一个名为CustomInstrumentation.xml的自定义插装文件,与CoreInstrumentation.xml并排放置。将以下内容添加到您的自定义插装文件中:

<?xml version="1.0" encoding="utf-8"?>
<extension xmlns="urn:newrelic-extension">
  <instrumentation>
    <tracerFactory name="NewRelic.Agent.Core.Tracer.Factories.BackgroundThreadTracerFactory" metricName="Category/Name">
      <match assemblyName="AssemblyName" className="NameSpace.ClassName">
        <exactMethodMatcher methodName="MethodName" />
      </match>
    </tracerFactory>
  </instrumentation>
</extension>

您需要更改上面的属性值:Category/Name、AssemblyName、NameSpace.ClassName和MethodName:
当来自程序集AssemblyName的类型为NameSpace.ClassName的对象调用方法MethodName时,事务开始。当该方法返回或抛出异常时,事务结束。事务将被命名为Name,并将分组到由Category指定的事务类型中。在New Relic UI中,您可以在查看监视>事务页面时从类型下拉菜单中选择事务类型。
请注意,Category和Name都必须存在,并且必须用斜杠分隔。
正如您所期望的那样,在方法调用期间发生的已经被仪器化的活动(方法、数据库、外部)将显示在事务的分解表和事务跟踪中。
以下是一个更具体的示例。首先是仪器化文件:
<?xml version="1.0" encoding="utf-8"?>
<extension xmlns="urn:newrelic-extension">
  <instrumentation>
    <tracerFactory name="NewRelic.Agent.Core.Tracer.Factories.BackgroundThreadTracerFactory" metricName="Background/Bars">
      <match assemblyName="Foo" className="Foo.Bar">
        <exactMethodMatcher methodName="Bar1" />
        <exactMethodMatcher methodName="Bar2" />
      </match>
    </tracerFactory>
    <tracerFactory metricName="Custom/some custom metric name">
      <match assemblyName="Foo" className="Foo.Bar">
        <exactMethodMatcher methodName="Bar3" />
      </match>
    </tracerFactory>
  </instrumentation>
</extension>

现在是一些代码:
var foo = new Foo();
foo.Bar1(); // Creates a transaction named Bars in category Background
foo.Bar2(); // Same here.
foo.Bar3(); // Won't create a new transaction.  See notes below.

public class Foo
{
    // this will result in a transaction with an External Service request segment in the transaction trace
    public void Bar1()
    {
        new WebClient().DownloadString("http://www.google.com/);
    }

    // this will result in a transaction that has one segment with a category of "Custom" and a name of "some custom metric name"
    public void Bar2()
    {
        // the segment for Bar3 will contain your SQL query inside of it and possibly an execution plan
        Bar3();
    }

    // if Bar3 is called directly, it won't get a transaction made for it.
    // However, if it is called inside of Bar1 or Bar2 then it will show up as a segment containing the SQL query
    private void Bar3()
    {
        using (var connection = new SqlConnection(ConnectionStrings["MsSqlConnection"].ConnectionString))
        {
            connection.Open();
            using (var command = new SqlCommand("SELECT * FROM table", connection))
            using (var reader = command.ExecuteReader())
            {
                reader.Read();
            }
        }
    }
}

这是一个简单的控制台应用程序,演示自定义事务:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Custom Transactions");
            var t = new CustomTransaction();
            for (int i = 0; i < 100; ++i )
                t.StartTransaction();
        }
    }
    class CustomTransaction
    {
        public void StartTransaction()
        {
            Console.WriteLine("StartTransaction");     
            Dummy();
        }
        void Dummy()
        {
            System.Threading.Thread.Sleep(5000);
        }
    }

}

请使用以下自定义仪表文件:
<?xml version="1.0" encoding="utf-8"?>
<extension xmlns="urn:newrelic-extension">
    <instrumentation>
        <tracerFactory name="NewRelic.Agent.Core.Tracer.Factories.BackgroundThreadTracerFactory" metricName="Background/CustomTransaction">
          <match assemblyName="ConsoleApplication1" className="ConsoleApplication1.CustomTransaction">
            <exactMethodMatcher methodName="StartTransaction" />
          </match>
        </tracerFactory>
        <tracerFactory metricName="Custom/Dummy">
          <match assemblyName="ConsoleApplication1" className="ConsoleApplication1.CustomTransaction">
            <exactMethodMatcher methodName="Dummy" />
          </match>
        </tracerFactory>
    </instrumentation>
</extension>

感谢您提供详细的答案。这基本上总结了我整天在文档中阅读的内容。目前,我的理解是没有办法使用类似于全局模式(即 *)的方法来监视所有代码。也就是说,任何给定类的任何调用方法都可以在不太具体地指定应用程序域的情况下进行监视。您能确认吗? - Ali
你好,你说得对,使用 * 来追踪所有内容是不可行的,因为这会消耗太多资源。 - karlpcrowley
我会继续并且肯定接受你的答案。请问是否有任何计划推出.NET的SDK,以便我们可以将其包含在我们的项目中自动跟踪事物?谢谢。 - Ali
我将为您提交一个功能请求,让我们的项目经理开始开发SDK。如果您想进一步讨论这个想法,建议您查看discuss.newrelic.com。 - karlpcrowley
1
@karlpcrowley - 有没有类似的针对基于PyQt的桌面应用程序的东西? - Sandeep

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接