Elastic APM .NET Agent Preview版が出た件

概要

www.elastic.co

GoやJavaPythonRubyといった言語にはAPMを実現するためのAgentが提供されていますが、.NET版はありませんでした。 まだPreview版、バージョンも0.0.1.0という代物ですが、.NET資産をお持ちの方、これから.NETCoreデビューしようとする方には朗報です。 これまで、Application Insightsしかないのか!と思っていた方にも、よいお知らせではないでしょうか。

以下の機能がサポートされていると書かれています。

  • ASP.NET Core 2.x
  • Entity Framework Core 2.x
  • Outgoing web requests with the HttpClient class on .NET Core

おっと、.NETFramwork4.7.xなどの人はどうしたら良いの? と気になる人もいるでしょう。 安心してください。.NET Standard2.0で提供されておりますよ。

This API is shipped as a .NET Standard 2.0 library, which means you can use it on every .NET flavour that supports .NET Standard 2.0. In the case of .NET Full Framework this is version 4.6.1 or newer, and in case of .NET Core this is version 2.0 or newer.

今回は、以下の点を確認して参ります。

  1. ASP.NET Core2.2に、Elastic APM .NETAgentを入れて動かすところ
  2. Outgoing のHTTPの確認
  3. EFCoreの確認

前提となる環境の準備

今回はAPM Agentの方を主としておりますので、APM ServerたElasticsearch、Kibanaについては既に構築済みであるものとします。

参考までにこちらで使ったdocker-composeファイルがこちら。

version: '2'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:6.6.0
    container_name: elasticsearch
    environment:
      - cluster.name=docker-cluster
      - bootstrap.memory_lock=true
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - esdata660:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
    networks:
      - esnet

  kibana:
    image: docker.elastic.co/kibana/kibana:6.6.0
    container_name: kibana
    ports:
      - 5601:5601
    depends_on:
      - elasticsearch
    links:
      - elasticsearch:elasticsearch
    networks:
      - esnet

  apm:
    image: docker.elastic.co/apm/apm-server:6.6.0
    container_name: apm
    ports:
      - 8200:8200
    links:
      - elasticsearch:elasticsearch
    networks:
      - esnet

volumes:
  esdata660:
    driver: local

networks:
  esnet:

ASP.NETの準備

ASP.NETプロジェクトの作成

このあたりは、.NETCoreをなさっている方には釈迦に説法ですので、スクロールしまくってください。 AngularでもReactでもAPM部分にはあまり関係がないと思います。今回は、オーソドックスなMVCのものを選択してプロジェクトを作りました。

f:id:tsgkdt:20190215011907p:plain
ASP.NET Core Web

f:id:tsgkdt:20190215012132p:plain

必要パッケージのインストール

VisualStudioの「ツール」-「NuGetパッケージマネージャ」ー「ソリューションのNuGetパッケージの管理」から必要なNuGetパッケージを選択、インストールします。

プレリリースを含めるにチェックを入れておくのがポイントです。

f:id:tsgkdt:20190215012512p:plain

  • Elastic,Apm.AspNetCore
  • Elastic.Apm.EntityFrameworkCore

の2つを入れましょう。

設定ファイルの変更

appsettings.jsonを編集し、APMサーバが動いている場所を指定します。
ElastcApmで宣言されている部分のServerUrlsのところです。

Urlsと複数系となっていますが単一のホストを指定するときは、以下の例のように文字列でそのまま書いて良いようです。

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ElasticApm": {
    "LogLevel": "Debug",
    "ServerUrls": "http://xxx.xxx.xxx.xxx:8200"
  }
}

Startup.csの変更

Startup.csにて、APM Agentを有効にします。
app.UseElasticApm(Configuration~)を1行足しています。

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
 {
      if (env.IsDevelopment())
      {
          app.UseDeveloperExceptionPage();
      }
      else
      {
           app.UseExceptionHandler("/Home/Error");
      }

      app.UseStaticFiles();
      app.UseCookiePolicy();

      //for Elastic APM
      // HttpDiagnosticsSubscriber -> 外部に出ていくHTTPを捕捉する
      // EfCoreDiagnosticsSubscriber -> EFCoreのリクエストを捕捉する
      app.UseElasticApm(Configuration,  new HttpDiagnosticsSubscriber(),  new EfCoreDiagnosticsSubscriber()););
            
      app.UseMvc(routes =>
      {
          routes.MapRoute(
              name: "default",
              template: "{controller=Home}/{action=Index}/{id?}");
      });
  }

これだけで、純粋なリクレストとレスポンス部分のAPMのメトリクスは取れるようになりました。

まとめると、大事な点は3つ。

  1. NuGetで必要パッケージをインストールしたところ
  2. APMサーバの場所を設定ファイルで指定したところ
  3. Startup.csでUseElasticAPMを呼び出しているところ

Out GoingのHTTPリクエストのための追加

外のサーバにさらにHTTPリクエストを投げ、その時間もタイムラインとして表示されることを確認するために、その部分を追加してみます。

HttpClientの追加

外部のサイトにGetを投げて、帰ってきたものをデバッグで出すだけ、という内容を追加しました。

private static HttpClient _client = new HttpClient();

public async Task<IActionResult> Index()
{
    var response = await _client.GetAsync("https://www.elastic.co/guide/index.html");
    System.Diagnostics.Debug.WriteLine(response.Content);
    return View();
}

EFCoreのテスト実装の追加

単純なEntityFrameworkCoreを使ったSELECT文を1件投げるものをBlogページとして追加しました。

public IActionResult BlogService()
{
     var context = new BloggingContext();
     var queryResults = context.Blogs.Where(x => x.BlogId == 1).First();
     Console.WriteLine(queryResults.Url);
     return View();
}

これで、動作を確認するためのASP.NETCoreの環境は作成できました。後は動かして、触っていきます。

確認

APM画面トップ

KibanaのAPMメニューを開いた直後の画面が、このように表示されます。Agentの箇所がdotNetとなっていることが確認できます。

f:id:tsgkdt:20190215020719p:plain

今回のプロジェクトの画面トップ

各URLに対してページの処理期間(duration)などが表示され、グラフも表示されていることが確認できます。

f:id:tsgkdt:20190215014142p:plain

外部にHTTPリクエストを飛ばしたものの確認

今回は、Index(Home画面)に、HttpClientで外部にGetを飛ばす処理を追加したので、このURLのトランザクション画面を確認すると、このようにelastic.coへのアクセスがTmelineにしっかり乗ってきていることが確認できました。

f:id:tsgkdt:20190215014648p:plain

EFCoreの確認

SQLの実行部分で101msかかっていると、表示されていることが確認できます。

f:id:tsgkdt:20190215020315p:plain

そのSQL部分をクリックすると、詳細の画面に遷移し、実際に発行されたSQLがどのようなものであったかなど、内容を確認することができます。

f:id:tsgkdt:20190215020503p:plain

おまけ

画面右上の「Ingerations」を押すと、MachineLearningやWatcherとの連携ができそうなメニューが表示されています。 連携して使うことで、より柔軟なAPMの実現が期待できますね。

f:id:tsgkdt:20190215020905p:plain

では、ハッピーElasticライフを!