.NET 6 と Daprを使った分散サービス開発 その5 Observability (観測可能性)

# Observability (観測可能性)によるマイクロサービスの状態観測とログ、分散トレーシング

今まで、以下の流れで作業を行ってきました。今回はDaprに備わっているObservability (観測可能性)を使って、各サービスの状態観測やモニタリングについて触れていきたいと思います。


**今までの前提の上で観測可能性機能を追加しますので、このページから読まれている方は、前提として以下を読んできてください。**

----

https://qiita.com/kazumihirose/items/016dde8ca9b35d1030cc

https://qiita.com/kazumihirose/items/e996e3cc34c511bc1124

https://qiita.com/kazumihirose/items/f7811bf3e5abe405a551

https://qiita.com/kazumihirose/items/57e3aeaab65a1a68977b

## Observability (観測可能性)の大事さ

Kubernetesなどの環境では、もちろんPersistentVolumeを用意して永続化ストアを持つことができなくもないですが、ログの為に永続化ストアを使うことは正直言ってあまりお勧めできる事では無いと思っています。また、各サービスがお互いに連携して動作するマイクロサービスのような設計の場合、どのサービスで例外が起こっているかなどをわかりやすく把握できる仕組みが大事ですし、できる事であれば運用に入る前の開発時から導入して効率よく開発を進めたいものです。

いわゆる分散トレーシングと呼ばれているものです、AzureですとApplication Insights, AWSだとX Ray, GoogleだとStackdriver 、New Relicなども良く知られたサービスです。

以下は、Azure Application Insightsという分散トレーシングのサービスの一画面です。エンドポイントのPath単位で、500エラーが何回発生しているかを集計してくれており、そしてログをドリルダウンする事ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24782/dbd8325f-36cb-929b-d258-8606a8c6a6ca.png)

これらのログをドリルダウンすると、ログの中から重複したエラーを整理してくれ、どの点で例外が発生したかコールスタックを表示してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24782/0596c392-c85a-364a-7aef-696f7f009e0d.png)

何かが起こって **ログを見る前に、何が起こっているのかを常にモニタして、可視化しましょう。**

## DaprでのObservability (観測可能性)

Daprでは、オープンソースプロジェクトであるOpenTelemetry での、W3C Tracing contextフォーマットでのログ収集の仕組みを実装しています。
各サービスから収集したトレース、メトリック、ログのデータは、Azure AppInsights, AWS X-Ray, StackDriver, Azure Monitor,Prometheus,Grafana,New Relic,FluentD,New Relic,Zipkin,Jaegerなどに連携する事ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24782/56ca4cd3-3204-3c1c-ce01-cd1f05bf5c9a.png)

## DaprでObservability (観測可能性)コンポーネントを設定する

ここでは、あらかじめdapr initでコンテナとしてロードされており、既にローカルに設定されているZipkinを使う設定をDaprに仕込みます。

注意として、今まで設定していたコンポーネントとしてのプロジェクト単位の設定では無く、Daprの全体設定となります。よって、以下に記載してください。同じようにKubernetes にもconfigmapとして設定できますが、それについては後のトピックとしたいと思います。

- %USERPROFILE%\.dapr\config.yaml (Windowsの場合)
- $HOME/.dapr/config.yaml (Linux/Macの場合)

```YAML:config.yaml
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: daprConfig
spec:
  tracing:
    samplingRate: "1"
    zipkin:
      endpointAddress: http://localhost:9411/api/v2/spans
```

あれ？既に書かれているよ？となっていた方は正解です。dapr initでローカル展開した際に自動的に設定してくれていたのでした。
そして、dapr initで展開されたdockerイメージの中でOpen Zipkinが既に稼働しています。

```bash
$ docker ps
CONTAINER ID   IMAGE               COMMAND                  CREATED      STATUS                       PORTS                              NAMES
ba8a9bdb62ab   daprio/dapr:1.6.0   "./placement"            2 days ago   Up About an hour             0.0.0.0:6050->50005/tcp            dapr_placement
808b6358b4e7   openzipkin/zipkin   "start-zipkin"           7 days ago   Up About an hour (healthy)   9410/tcp, 0.0.0.0:9411->9411/tcp   dapr_zipkin
bed085e54a77   redis               "docker-entrypoint.s…"   7 days ago   Up About an hour             0.0.0.0:6379->6379/tcp             dapr_redis
```

## Open Zipkinで確認しよう

Open Zipkinで分散トレーシングログを確認してみようと思います。まぁ、ログといえるほどのログやアクセスが無いので、とても質素で貧相ですが・・・

URL http://localhost:9411/ にアクセスしてみてください、以下のような画面が表示されると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24782/c073fd9c-9bbb-1fb6-49fe-485c5cde6425.png)

とりあえず、何も考えずに**RUN QUERY**をクリックします。各サービスが一覧となって、Durationなども表示されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24782/976d13cd-4604-e9fb-2427-dbe092703a23.png)

ギアマークから、過去何日間のログを出すかなどフィルタに関しての設定もできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24782/d3ef4a97-a60c-453d-5fde-0ec159d617df.png)

Dependenciesからは、ログから得られるサービス間の依存関係なども表示されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24782/a3d64a00-8621-f290-5a97-8d38cebf6567.png)

## プロジェクトが吐き出すログ設定を変更する

何故、動いていたのにログがほとんどなかったのか？というのは、実は各プロジェクトからログの出力設定を行っていなかったからです。
各プロジェクトに **Program.cs** の先頭に以下のログのフォーマット設定2行を追加します。
```
using System.Diagnostics;
Activity.DefaultIdFormat = ActivityIdFormat.W3C;
```

```csharp:Program.cs
using System.Diagnostics;
Activity.DefaultIdFormat = ActivityIdFormat.W3C;

var builder = WebApplication.CreateBuilder(args);
// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Add Dapr Client
builder.Services.AddDaprClient();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

```

## Open Zipkinで再度確認

設定を終えたら、 **tye run** でプロジェクトと起動しましょう。
Tye dashboardから、http://localhost:8000/　にアクセスして、エンドポイントを確認します。
ここでは、AppのSwaggerにアクセスしたいので　https://localhost:49689/swagger にアクセスしましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24782/10584e0c-cbae-9d68-532a-914a7579dabf.png)

アクセス出来たら、試しにAPIへ何度かGETしてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24782/e01a054d-a297-82a8-c5b1-a2bd366013a1.png)

次にZipkinへアクセスしましょう。http://localhost:9411/です。
RUN QUERYを押すと、ログが出てきましたね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24782/5b6b70d3-a747-6266-f095-029cf2955d97.png)

トレースと各サービスにコールする際のレイテンシなども出力されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24782/8163976e-63e5-570a-50cf-4a1294a58fd3.png)