gRPC server (Ruby) でinterceptorを用いたSentryインテグレーション実装

サービスの運用・保守にあたり、 Run-timeのエラーログ収集はとても重要なタスクです。
ログ全体からエラー発生部分を抽出し監視することもできますが、エラーログの収集に特化したサービスとしてSentryが便利です。
Web画面からスタックトレースを確認し、ユーザID等の補足情報をもとにバグ修正を行うことが可能です。

最近、golangでgRPCサーバーを実装する機会があり、エラートラッキングにSentryを採用しました。 十分に情報がまとまっておらず(Sentry x gRPCは事例がまだ少ない?)、実装にすこし手こずったのでその経験を記します。

またgRPCサーバーで簡単にSentryインテグレーションを行うためのライブラリsentry-raven-grpcを公開しましたのでその紹介をします。

Sentry 公式ドキュメント

golangのSDKに関してはまだ開発段階とのことですが、公式ドキュメントに簡単な説明が記されています。

とくにgolang標準のnet/httpライブラリを用いたWebアプリケーション実装に対しては、ミドルウェアも提供されています。 ただしpanicの利用が前提となっているようで、golangのスタンダードから外れている感じを否めません。

当然ながら、Sentryのgolang SDKのリポジトリを覗いてみても、gRPCサーバーのインテグレーションに関する説明は見当たりません。

愚直な方法

golangでgRPCサーバーを実装する場合、各サービスメソッドはserver structをレシーバとする関数(以降handlerと呼びます)として記述します。
📝 https://github.com/grpc/grpc-go/blob/v1.21.x/examples/helloworld/greeter_server/main.go#L40-L44

// server is used to implement helloworld.GreeterServer.
type server struct{}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    log.Printf("Received: %v", in.Name)
    return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}

愚直にSentryインテグレーションを行おうとすると、すべてのhandlerに対してエラー補足処理を記述する必要があります。 少し工夫してエラー補足処理をヘルパー関数として括りだすこともできますが、handlerごとにヘルパー関数の呼び出しが必要となりDRYでありません。

sentry-raven-grpc

本記事のメインです。

上記のとおり愚直な方法でgRPCサーバー向けのインテグレーションすると、handlerごとに処理が重複しDRYでないという問題がありました。
そこで、gRPCで利用可能な機能 "Interceptor" 用いることで上記問題を解決しSentryインテグレーションを実装しました。

golangのgRPCサーバー実装ではInterceptorが利用できます (オフトピックですがrubyでもInterceptor APIが提供されています)
Interceptorはhandlerをラップし、その実行前後に処理を挟むレイヤとして機能します。

Interceptorに関してはすでにいくつか記事が存在するため詳しい説明は割愛します。
ちなみにInterceptorの利用例としては下記のリポジトリにまとめられています。
https://github.com/grpc-ecosystem/go-grpc-middleware
handlerの実行前後に処理を挟み込めるという性質を活かし、認証・認可機能やモニタリングの用途として活用されているようです。

拙作 sentry-raven-grpcでもInterceptorを用いてSentryインテグレーションを行います。
難しいことは一切なく、たったひとつの図で説明が終わります。
handlerはpanicを利用する必要はなく、golangのお作法どおりに呼び出し元にerrorを返すように記述できます。 interceptor

メインとなるコードは高々10行程度しかありません。 引数として渡されるhandlerを実行し、返されるerrorを捕捉してsentryに報告します。
📝 https://github.com/sat0yu/sentry-raven-grpc/blob/1e8cb0c/interceptor.go#L13-L22

ポイントとして、sentry-raven-grpc では新たに ErrorCapturer インタフェースを定義し、SDKが提供する捕捉メソッド CaptureErrorを抽象化しています。 これによりSDK部分をmockしてテストが書きやすくしています。

セットアップは非常に簡単で、Sentry DSNを渡してServerOptionを生成しgRPCサーバー生成時に設定するだけで済みます。 具体的にはこちらのcommitが参考になるかと思います。

StackTraceが途中で切れる

Sentryインテグレーション自体はできたものの、いざ収集されたエラーを確認してみるとStackTraceが不十分という問題がありました。
Sentry上ではsentry-raven-grpcで補足した時点からのStackTraceしか確認できず、バグ修正には全く意味のない情報です。
この問題はgolang標準の"errors"ではなくgithub.com/pkg/errorsを利用することで回避できます。

StackTraceが消えてしまう(集められない)理由に関する詳しい調査はできていませんが、判明し次第追記するつもりです。

ブログ再開宣言から一年が経ちました

 久しぶりにブログを書こうと思いたち、確認したところ、ちょうど一年前にブログ再開宣言記事を書いていたことが判明した。 我が事ながら再開宣言をしていたこと自体を完全に忘れており、無論、一本も書けないままあっという間に一年が経過してしまった。

 このままでは笑い話どころかクソの役にも立たず、自分自身非常に恥ずかしい気持ちを抱いている。 そこで本記事では、一本もブログを書くことができなかったのか原因を探り、改善を図る。

 今年こそは有言実行を果たしたい。こんな恥ずかしい思いはこりごりだ。 具体的には今年は最低でも月に2本=年12本は執筆したい。

続きを読む

golangでLSystemを実装した

会社で有志が集まり毎週木曜の就業後にgolangのハッカソンが行われている。 僕も数週間前からジョインした。

今からキャッチアップするには遅すぎる感も否めないのだけど。。 型があって、多機能で、並列化も簡単に実現できちゃうgolangは十分に興味をそそる。

先日のハッカソンでは以前から気になっていたLSystemを実装した。 もう名前がかっこいい。植物など自然界の構造物をうまく記述できる形式文法。かっこいい。 FCGなので実装も簡単だろうと思いgolangで書いてみた

golangは非常に多機能で、標準ライブラリで画像生成まで簡単にできてしまう。 ついでにwikiに乗っているコッホ曲線を真似てLSystemで生成した文字列を画像化してみた。 f:id:sat0yu:20180526130632j:plain

こういう書き捨てのプログラミングはストレス解消にもってこいだ。

与えること、まずはそれから。

与えることは、自分と世界との接点をつくる大切な営みです。
与えることによって、自分で自分自身の存在を感じることができます。

目まぐるしく過ぎて行く日常の中で、我々はときとして自分と世界との境界を見誤ってしまいます。
「どうしてあなたは○○しないの?■■すべきだよ」
「△△が忙しくて●●してる時間がないんだ」

自我が肥大化して、他者を思いやることができなくなってしまうこともあります。
あるいは逆に、世界に圧倒されて自分自身をひどく矮小化してしまうこともあります。
そしていずれの場合でも、我々の心には大きな負担がかかります。

他者に自分を重ねすぎて、思い通りにいかないと悲しんだり、怒ったりして感情に突き動かされることもあります。
また、自分ではこの状況をどうにもできないと自信喪失し、途方も無い不安や孤独感に襲われることもあります。

だからこそ、我々は自分と世界との境界に関して注意を向けなければいけません。
そしてその一助となるのが「与えること」なのです。
我々は与えることによって世界と能動的に向き合うことができます。

一般に二者の関係においては、一者が能動的、もう片方が受動的であると見ることができます。
自分と世界との境界のバランスが崩れている状態は、別の見方をすれば、我々は受動的になりすぎているのです。

自分を重ねすぎた他者がどのように行動するかによって影響”される”
自身の力ではどうにもできないと感じる世界によって圧倒”される”
「自分と世界との境界を見誤っている状況」を説明するとき、その多くは受動態で表現されます。

物体、時間、存在、あらゆるものに対して「与える」という動詞を使うことができます。
加えて「与える」ことは暗に与えられる側を想定しています。「自分が、世界に、〜を、与える」という具合に。
言葉あそびではありません。与えるという行為を実行するとき、そこには必ず「誰に」と「何を」が存在しているのです。
そして「今日自分が何をしたのか」と振り返るとき、同時に「誰に」と「何を」の存在が頭に浮かんできます。

与えるという行為によって、我々は能動的に世界と関わることができるようになります。
与えるという行為のたびに、我々は自分自身を認知できるのです。
言い換えれば、自分と世界との境界をニュートラルな状態に戻すことができるのです。

そのモノサシは誰のもの?社会的証明という諸刃の剣

あなたは米国首相の入国規制令に賛成ですか?

人がある物事に対して肯定的(否定的)な態度をとるとき、その理由としては以下の2つが挙げられます。

  • ①自らが肯定的(否定的)な印象・考えを持っている場合
  • ②社会通念として否定的(肯定的)な態度をとらないほうが懸命と考えられる場合

①は説明の必要などありません。肯定的に考えているのだから、肯定的な態度を示しているだけです。 ②は自身が所属する「コミュニティにおける常識」から尤もらしい態度をとっている場合です。 つまり、「コミュニティの大半が『良し』とするのだから、きっとそれが『良い』のだろう」と価値判断(モノサシ)を代替しているのです。 名著「影響力の武器」では②のような状況を指して「社会的証明」として紹介しています。

今日の情報化社会において、「社会的証明」は大変便利な手段です。 不確かな状況においてもなお、我々は周囲の判断を参考にすることで大まかな方向性を掴むことができるのです。 ただし注意しなければならないのは、ときとして「社会的証明」は我々の平衡感覚を狂わせることがあるということです。

例えば冒頭の入国規制のように、(少なくとも日本人の大多数に限っては)自分とかけ離れたトピックに関して他から判断基準を借用したところでさほど問題になることはありません。 ところが、個人の人格と密接に結びつく話題に関して「社会的証明」を適用し、たとえ一時的だとしても他者のモノサシを借用することは、自己アイデンティティを否定することにも繋がりかねません。

次の問いに対して、あなたはどう考えますか?

あなたは善い人間ですか?あなたは悪い人間ですか?

「友人にはよく優しい人だと言われるし、優しい人間は概して善い人間だから、私は善い人間だ」 例示としてはお粗末かもしれませんが、これに類する思考をしたのであれば危険サインです。 これはまさに「社会的証明」を自己認識に適用したケースに他なりません。 自分の外側に存在するモノサシを使って、自己認識を形成しているのです。

「私はこの世界の中心なんだから自分は善い人間にきまっている」 分かりやすいように、こちらもあえて極端な例を引き合いに出しました。 この例のように、自分のモノサシを使って自己認識を規定することができる人は、そうでない人と比べて精神的健康に恵まれているかもしれません。 自らに外在するモノサシでない以上は、誰かに押し付けられることもなければ、意志と反して変化することもないからです。

「影響力の武器」では、「『社会的証明』は不確実な状況おいてより強く作用する」と述べられています。 未経験な領域でのできごとや、不完全な情報しか得られていないような状況では、我々はついつい周囲の様子を伺い「社会的証明」を適用しようとしてしまうのです。 もしかしたら、入社間もない新人社員が精神に不調をきたしてしまう要因の一つも、ここにあるのかもしれません。

毎日精一杯働いても仕事がなかなか終わらず、残業ばかりの日々を過ごす一年目の社会人を考えてみます。 彼以外の入社同期は、3人とも毎日きちんと仕事をこなして定時に退社を済ませています。 「社会的証明」の罠に嵌ったこの新卒社員は、例えどれほど違和感があっても、例えどれほど不条理を感じていても、おそらく声を上げることはないでしょう。 「社会的証明」によって、定時であがる他の同期3人こそ「正常」であって、自分は「異常」であると示されているからです。

程度の差はあれど、我々の多くは人生の節々においてこのような状況をしばしば体験してきているはずです。 幸い、この状態はしばらくすれば自然と解消されます。 環境に慣れるにつれて不確実性が少なくなり、一方で自らの考えが深まり、「社会的証明」に頼る必要がなくなるからです。

とはいえ状況を楽観視してばかりもいられません。 なぜなら「社会的証明」は多くの場合で無意識的に利用されるからです。 「社会的証明」に頼ってしまったときには。「何に対して社会的証明を適用したのか」という部分に注意を払うことで、絶えず平衡感覚を失わないようにしなければならないのです。

社会的証明=借り物のモノサシを盲信して自己アイデンティティを否定しつづければ、やがて自我は弱まり精神は衰弱してしまいます。 一方で、自分のモノサシを自分の外側世界に押し付けてばかりいては、社会不適合者のレッテルを貼られてしまうこともあるかもしれません。

孤独と感性と理性

どのような瞬間に孤独を感じますか?
あなたが今感じている孤独は、ほんとうは自分の中に生じた感情を蔑ろにしているだけなのではないですか?

孤独を感じるとき

忙しくて苦しい、あるいは何かを失って悲しいなど、人は不幸な感情に晒されたときにふと強い孤独を感じることがあります。
対して、幸福な状態、つまり何かに熱中しているときや満ち足りているときに孤独を感じるという人は聞いたことがありません。

幸福な状態でも、誰かと幸せを分かち合いたい(のに、そうできない)と思ってしまうことで孤独を感じるという人もあるかもしれません。
仮に分かち合えないことが原因で孤独を感じているのだとすれば、それは実際には対象の出来事自体がその人にとって本当の意味での幸福ではないのでしょう。
なぜなら、その人は少なくとも、対象の出来事よりも「分かち合える人間関係」に対して幸福を感じているからです。

受け止めれば、何てことはない

冷たい風が吹く冬の日には、不快を感じて反射的に肩を縮め、思わず「寒い」「早く中に入りたい」と口にしてしまいます。
しかし、ひとたび反射的であることを止め、意識的に「『寒さ』の存在」を捉えてしまえば、先ほどまで感じていた「不快」は消え去ります。 むしろ、寒さが肌を刺す感覚から生きている喜びを感じることだってできます。

「孤独と不幸」も「不快と寒さ」の関係と同じように考えることはできないでしょうか。

人が孤独だと感じるとき、その後ろ側には孤独を感じる引き金となった何か不幸な出来事の存在を疑ってみます。
原因となった出来事を意識的に受け止めることができれば、「不快」同様に「孤独」もすうっと消えてしまうものです。

自分と向き合えないと余計に孤独を強く感じる

好ましくない出来事を意識的に受け止めることは、そう簡単にできることではありません。 多くの人は見てみぬフリをしてやり過ごしているのではないでしょうか。

人間の誇るべき適応能力によって、年をとるにつれ自分を騙す術もうまくなります。
大人へと成長する中で、いつからか感性は理性によってネグレクトされるようになります。
内面の二者(感性と理性)の間でさえ離別しているのだから、孤独を余計に強く感じてしまっても不思議ではありません。

ここで重要なのは、理性=自らの意志ひとつで、孤独という感情を弱めも強めもできてしまうということです。