SlideShare a Scribd company logo
Implements OpenTelemetry Collector in DotNet
河合 宜文 / Kawai Yoshifumi / @neuecc
Cysharp, Inc.
Cygames
C#大統一理論
C#
Implements OpenTelemetry Collector in DotNet
Unified Realtime/API Engine for .NET Core and Unity
https://github.com/Cysharp/MagicOnion/
gRPCベースのC#特化ネットワークフレームワーク
.NET Core(Server) - Unity(Client)における
ハイパフォーマンスなAPI通信とリアルタイム通信を実現
gRPCなのにProtocol Buffersを使わない(スキーマ共有としてC#
コードそのものをサーバー/クライアントでシェアする)という
C#ファーストな設計(シリアライズ自体はMessagePackで行う)
public class TestService : ITestService
{
public async UnaryResult<int> Sum(int x, int y)
{
return x + y;
}
}
var client = MagicOnionClient.Create<ITestService>(channel);
var result = await client.Sum(100, 200);
public interface ITestService
{
UnaryResult<int> Sum(int x, int y);
}
Share Service Definition(and
Requst/Response Message) written in C#
Server Implementation
Client Implementation
Implements OpenTelemetry Collector in DotNet
MagicOnion
Datadog
自社アプリのためだけ、なら、特定の
サービス専用のコレクターを用意するだ
けでいいんですが……
MagicOnion
Datadog
New Relic
Application Insights
Mackerel
CloudWatch
Stackdriver
Prometheus
Zipkin
フレームワーク作者としてこんなにいっぱいは
用意できない(し、ユーザー数的に誰かが作っ
てくれることもそう期待できない)
Datadog
New Relic
Application Insights
Mackerel
CloudWatch
Stackdriver
Prometheus
Zipkin
MagicOnion
ここの部分(Collector)を提供する
だけでOK
ここの部分(Exporter)は標準/準標
準が出揃う(はず)
Implements Collector
1リクエスト内の細かい挙動(DB通信部分/HTTP通信
部分など)が範囲(Span)ごとにタイムライン表示さ
れる。分散トレーシングではなく単一アプリケー
ションでも、細かいボトルネックを探りやすい有
用な可視化
数値データ(Sum/Min/Max/Avg/Count)のグラフ化。
インフラ監視だけでなくアプリケーションモニタ
リングとしても傾向を見るのに有用な可視化
public class OpenTelemetryCollectorFilter : MagicOnionFilterAttribute
{
public override async ValueTask Invoke(ServiceContext context)
{
try
{
// ここに前処理
await Next(context);
// ここに正常時処理
}
catch (Exception ex)
{
// ここに例外時処理
}
finally
{
// ここに後処理
}
}
}
MagicOnionではFilterとしてリクエスト前後のフック
ポイントを用意しているので、これに引っ掛ける
var tracer = context.ServiceLocator.GetService<ITracer>();
var sampler = context.ServiceLocator.GetService<ISampler>();
var spanBuilder = tracer.SpanBuilder(context.CallContext.Method, SpanKind.Server);
if (sampler != null)
{
spanBuilder.SetSampler(sampler);
}
using (spanBuilder.StartScopedSpan(out var span))
{
try
{
span.SetAttribute("component", "grpc");
span.SetAttribute("request.size", context.GetRawRequest().LongLength);
await Next(context);
// 次ページに続く
ITracerとISamplerを取得(これは
MagicOnionのDIより。取得方法は
なんでもいい)
名前をつけてSpanを作る。フレー
ムワークのルートなのでルートで
しょという扱い(分散トレーシン
グ対応する場合は親の設定などが
必要ですが今回は割愛)
名前はサービスメソッド名(gRPC
なのでTestService/Sumなどになる)
var tracer = context.ServiceLocator.GetService<ITracer>();
var sampler = context.ServiceLocator.GetService<ISampler>();
var spanBuilder = tracer.SpanBuilder(context.CallContext.Method, SpanKind.Server);
if (sampler != null)
{
spanBuilder.SetSampler(sampler);
}
using (spanBuilder.StartScopedSpan(out var span))
{
try
{
span.SetAttribute("component", "grpc");
span.SetAttribute("request.size", context.GetRawRequest().LongLength);
await Next(context);
// 次ページに続く
Trace処理は軽い処理ではないので、間引く
場合はSamplerを渡せば、それのルール
(1/10の確率、とか)に則って処理される
スコープで囲んでいる範囲が自分のSpanにぶら
下がる雰囲気になる。サービスフレームワーク
なのでリクエスト開始から完了までを囲む
SetAttributeでSpanに情報を付与。この場合
gRPCですよ、とかリクエストサイズは何
バイトとでしたよ、とか。命名は自由、に
みえて仕様である程度は決まってる。
using (spanBuilder.StartScopedSpan(out var span))
{
try
{
// 中略
await Next(context);
span.SetAttribute(“response.size”, context.GetRawResponse().LongLength);
span.SetAttribute(“status_code”, (long)context.CallContext.Status.StatusCode);
span.Status = ConvertStatus(context.CallContext.Status.StatusCode)
.WithDescription(context.CallContext.Status.Detail);
}
catch (Exception ex)
{
span.SetAttribute(“exception”, ex.ToString());
span.SetAttribute(“status_code”, (long)context.CallContext.Status.StatusCode);
span.Status = ConvertStatus(context.CallContext.Status.StatusCode)
.WithDescription(context.CallContext.Status.Detail);
}
}
ステータスコードの指定。このステータスコード
はgRPCと一緒(と、仕様に書いてある)で、
Ok, Unknown, NotFoundなどがある
MagicOnionではIMagicOnionLoggerとして構造化ログ
の口を用意しているので、これを用いる。
public interface IMagicOnionLogger
{
void BeginBuildServiceDefinition();
void EndBuildServiceDefinition(double elapsed);
void BeginInvokeMethod(ServiceContext context, byte[] request, Type type);
void EndInvokeMethod(ServiceContext context, byte[] response, Type type, double elapsed,
void BeginInvokeHubMethod(StreamingHubContext context, ArraySegment<byte> request, Type t
void EndInvokeHubMethod(StreamingHubContext context, int responseSize, Type type, double
void InvokeHubBroadcast(string groupName, int responseSize, int broadcastGroupCount);
void WriteToStream(ServiceContext context, byte[] writeData, Type type);
void ReadFromStream(ServiceContext context, byte[] readData, Type type, bool complete);
}
public class OpenTelemetryCollectorLogger : IMagicOnionLogger
{
static readonly IMeasureDouble UnaryElapsed = MeasureDouble.Create
("MagicOnion/measure/UnaryElapsed", "Unary API elapsed time.", "ms");
static readonly IMeasureLong UnaryResponseSize = MeasureLong.Create
("MagicOnion/measure/UnaryResponseSize", "Unary API response size.", "
static readonly IMeasureLong UnaryErrorCount = MeasureLong.Create
("MagicOnion/measure/UnaryErrorCount", "Unary API error Count.", "num"
static readonly TagKey MethodKey = TagKey.Create("MagicOnion/keys/Method");
readonly IStatsRecorder statsRecorder;
readonly ITagger tagger;
readonly ITagContext defaultTags;
public OpenTelemetryCollectorLogger(IStatsRecorder statsRecorder, ITagger tagger, ITagConte
{
this.statsRecorder = statsRecorder;
this.tagger = tagger;
this.defaultTags = defaultTags ?? TagContext.Empty;
}
// 実装は次ページ
}
メトリックに使うKeyの類は事前用意
使う型はIStatsRecorderとITagger
public class OpenTelemetryCollectorLogger : IMagicOnionLogger
{
ITagContext CreateTag(ServiceContext context)
{
return tagger.ToBuilder(defaultTags)
.Put(MethodKey, TagValue.Create(context.CallContext.Method)).Build();
}
public void EndInvokeMethod(ServiceContext context, byte[] response,
Type type, double elapsed, bool isErrorOrInterrupted)
{
var map = statsRecorder.NewMeasureMap();
map.Put(UnaryElapsed, elapsed);
map.Put(UnaryResponseSize, response.LongLength);
if (isErrorOrInterrupted)
{
map.Put(UnaryErrorCount, 1);
}
map.Record(CreateTag(context));
}
// 他の実装は省略
}
MeasureMapを作って、値をPut。キーは事
前定義しているもの。
最後にTagと共にRecord。
ダッシュボード作りにはTagの設計が肝
要なのですが本題ではないので割愛
Conclusion
流行れ!今すぐ!
ちゃんとしたCollectorを一つ実装しておけば、ユーザーの使うあら
ゆるダッシュボードに対応できる……。夢見てた理想だ……。
C#でも勿論使えます
SDK: https://github.com/open-telemetry/opentelemetry-dotnet/
まだalphaなので正直怪しいというか実装TODOも多いので、まだ実
用的ではないですがOpenTelemetryのローンチは9月ですし!?
標準でRedis/Http/DBとASP.NET(ウェブフレームワーク)のCollector
が、ExporterはPrometheus, Stackdriver, Zipkin, ApplicationInsights
向けのものが提供される模様。
Implements OpenTelemetry Collector in DotNet

More Related Content

PDF
MagicOnion~C#でゲームサーバを開発しよう~
PDF
Unity C#と.NET Core(MagicOnion) C# そしてKotlinによるハーモニー
PDF
True Cloud Native Batch Workflow for .NET with MicroBatchFramework
PPTX
Using or not using magic onion
PDF
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
PDF
Multipeer connectivityを使った 動画のリアルタイム端末間共有
PDF
How to Make Own Framework built on OWIN
PDF
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
MagicOnion~C#でゲームサーバを開発しよう~
Unity C#と.NET Core(MagicOnion) C# そしてKotlinによるハーモニー
True Cloud Native Batch Workflow for .NET with MicroBatchFramework
Using or not using magic onion
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
Multipeer connectivityを使った 動画のリアルタイム端末間共有
How to Make Own Framework built on OWIN
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践

What's hot (20)

PDF
AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践
PDF
The Usage and Patterns of MagicOnion
PDF
MagicOnion入門
PDF
The History of Reactive Extensions
PDF
A quick tour of the Cysharp OSS
PDF
NextGen Server/Client Architecture - gRPC + Unity + C#
PDF
20190604 Containerized MagicOnion on kubernetes with Observability with New R...
PDF
Photon Server Deep Dive - PhotonWireの実装から見つめるPhotonServerの基礎と応用
PDF
Building the Game Server both API and Realtime via c#
PDF
.NET最先端技術によるハイパフォーマンスウェブアプリケーション
PDF
【Unite Tokyo 2019】Understanding C# Struct All Things
PDF
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
PDF
LINQPad with LINQ to BigQuery - Desktop Client for BigQuery
PDF
Introduction to NotifyPropertyChangedGenerator
PDF
ライブラリ作成のすゝめ - 事例から見る個人OSS開発の効能
PDF
A Framework for LightUp Applications of Grani
PDF
UniRx - Reactive Extensions for Unity
PDF
LightNode - Micro RPC/REST Framework
PDF
linq.js - Linq to Objects for JavaScript
PDF
The History of LINQ
AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践
The Usage and Patterns of MagicOnion
MagicOnion入門
The History of Reactive Extensions
A quick tour of the Cysharp OSS
NextGen Server/Client Architecture - gRPC + Unity + C#
20190604 Containerized MagicOnion on kubernetes with Observability with New R...
Photon Server Deep Dive - PhotonWireの実装から見つめるPhotonServerの基礎と応用
Building the Game Server both API and Realtime via c#
.NET最先端技術によるハイパフォーマンスウェブアプリケーション
【Unite Tokyo 2019】Understanding C# Struct All Things
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
LINQPad with LINQ to BigQuery - Desktop Client for BigQuery
Introduction to NotifyPropertyChangedGenerator
ライブラリ作成のすゝめ - 事例から見る個人OSS開発の効能
A Framework for LightUp Applications of Grani
UniRx - Reactive Extensions for Unity
LightNode - Micro RPC/REST Framework
linq.js - Linq to Objects for JavaScript
The History of LINQ
Ad

More from Yoshifumi Kawai (17)

PDF
A Brief History of UniRx/UniTask, IUniTaskSource in Depth
PDF
Deep Dive async/await in Unity with UniTask(EN)
PDF
Memory Management of C# with Unity Native Collections
PDF
Deep Dive async/await in Unity with UniTask(UniRx.Async)
PDF
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
PDF
Binary Reading in C#
PPTX
RuntimeUnitTestToolkit for Unity(English)
PPTX
RuntimeUnitTestToolkit for Unity
PDF
How to make the Fastest C# Serializer, In the case of ZeroFormatter
PDF
ZeroFormatterに見るC#で最速のシリアライザを作成する100億の方法
PDF
ZeroFormatter/MagicOnion - Fastest C# Serializer/gRPC based C# RPC
PDF
What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...
PDF
Photon Server Deep Dive - View from Implmentation of PhotonWire, Multiplayer ...
PPTX
Clash of Oni Online - VR Multiplay Sword Action
PDF
History & Practices for UniRx(EN)
PDF
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
PDF
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
A Brief History of UniRx/UniTask, IUniTaskSource in Depth
Deep Dive async/await in Unity with UniTask(EN)
Memory Management of C# with Unity Native Collections
Deep Dive async/await in Unity with UniTask(UniRx.Async)
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
Binary Reading in C#
RuntimeUnitTestToolkit for Unity(English)
RuntimeUnitTestToolkit for Unity
How to make the Fastest C# Serializer, In the case of ZeroFormatter
ZeroFormatterに見るC#で最速のシリアライザを作成する100億の方法
ZeroFormatter/MagicOnion - Fastest C# Serializer/gRPC based C# RPC
What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...
Photon Server Deep Dive - View from Implmentation of PhotonWire, Multiplayer ...
Clash of Oni Online - VR Multiplay Sword Action
History & Practices for UniRx(EN)
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
Ad

Implements OpenTelemetry Collector in DotNet