私が歌川です

@utgwkk が書いている

グリッチアイコン

グリッチコンポーネント便利で、今すぐアイコンを常時グリッチさせないといけない、というのにすぐ対応できる。

engineering.linecorp.com

<script src="https://unpkg.com/@uit/glitch-image@0.0.9/dist/glitch-image/glitch-image.js"></script>
<div style="width: 384px; height: 384px; margin: 0 auto;"><glitch-image src="https://i.gyazo.com/b7086c4e065efda64f7d06311fa418af.png"></glitch-image></div>

お酒を飲むと皮膚がただれる

お酒を飲むと皮膚がただれてしまい、2日かけて治している。ということは毎日飲酒してると一生皮膚がただれたままになると思う。なぜ皮膚がただれるのか、皮膚が弱いことは知ってるけどお酒とどう関係があるのか、そもそもお酒が原因なのかはまだ特定できていない。

もう3日ぐらいずっとこの調子なのでちゃんと寝られてない。助けてくれ!!!!!!!

体調 - 私が歌川です

皮膚の調子が悪かったころの記事を読むと、睡眠が取れていないことがよく分かる。あまりに悲惨でかわいそう。今はここまでひどい状態ではない。

1年ぐらい皮膚科に行ってなくて、保湿クリームを塗って飲酒せずに寝たら基本的になんとかなっている。

友だちの内定を定期ツイートで祝う風習

風習があって、毎週2回ツイートしていたのだけれど、自分の内定祝いだと勘違いされてしまった(そう思うのが自然だと思う)ので、これ以上誤解を生まないために止めます。

1年半ぐらいずっと止めずに続けていたらしくておもしろい。内定は欲しい。

twilog.org

いつも「時間がない」あなたに 欠乏の行動経済学

この本は id:Pasta-K さんに誕生日プレゼントとしていただきました。


お金や時間が足りない、ダイエットのようにやりたいことを我慢していてできない状態、をリソースが足りない状態、欠乏であるとしている。欠乏状態では、喫緊の課題を解決するための集中力は上がる(集中ボーナスと呼ぶ)が、少し先の重要だが緊急でない課題は後回しにされる(トンネリングと呼ぶ)。借金の返済が終わらない、給付金の申し込みができない、常に予定が埋まっている、というのをこの本では欠乏の罠と呼んでいる。

荷造りをしているときに、余裕のあるかばんに対して何を入れて何を後回しにするか考えることはない。欠乏の罠に陥らないためには、このような余裕(スラックと呼ぶ)が常にあることが重要であるとしている。突然の出費に対して貯金が足りないと借金をするしかなくなり、借金返済のことしか考えられなくなってしまう。常に欠乏状態にあるわけでもない人が欠乏状態に陥ってしまうのは、豊かな時期にスラックを作らないためである、というのも印象的だった。

欠乏状態にあるとき、目先の課題を解決するための集中力はすさまじいが、将来のことはまったく考えられなくなる、というのは身に覚えがあって、さまざまな実験や事例によってこれが普遍的な現象であることが示されていた。怠慢のためにやらないとか、方法を知らないとかではなく、処理能力に多大な負荷がかかっているので考えが及ばない、といったほうが近い。スケジュールでジェンガをやるようになったらもう追い込まれている、ということ。

この本のあとがきや解説のセクションも集中ボーナスによって書かれている、というのが伏線回収しててよかった。学部時代はよく生きていたなと思うけど、いま考えるとだいぶトンネルの中にいたと思う。

scrapbox.io

バーチャルYouTuberの配信を見ていない

最近はぜんぜんバーチャルYouTuberの動画や配信を見ていない。生配信を見つづける時間や根気がないというのが大きくて、アーカイブを見るとしても何時間もある配信を見て、みどころを探して楽しむ、というのはなかなか大変。野生の切り抜き動画を見ても本人の動画の再生回数が増えるわけではないけれども、その方が分かりやすくて楽しみやすい。

バーチャルYouTuberが嫌いになったというよりは、飽きたとか、ついて行けなくなったというほうが正しそう。もともと長い生配信を見まくってたというわけでもない気がするし、みんなが配信をしまくるようになった頃からちょっとずつついて行けなくなっていたと思う。バーチャル存在が歌う動画ばかり見ている。歌ってみたは何時間もないので気楽に見れる。

サークルの自分の分報チャンネルにVTuber情報が集まってくるようにPurposeを設定していたのだけれど、ついにやめた。最近はもう見ていない情報のほうが多く貼られるようになったし、別のチャンネルがあるのでそっちでやったほうがチャンネル名と目的が合っていると思う。

blog.utgw.net

むかしはバーチャルYouTuber全員が魔王魂の楽曲に合わせて謎の応援ソングを歌っていた、という記事を書いてたのを思い出したので記念に貼っておきます。大昔のことのように感じられるけど2年前の話なのでめっちゃ昔というわけでもない。

【追記あり】echoでNew Relicのエージェントを使えるようにするミドルウェアを書いた

追記

nrechoというライブラリが公式から提供されているのでこっちを使ったほうがよいと思います。わざわざ自前実装をしてから見つけてしまったけど見つけられたのはよかったということでここはひとつ……。

そういうわけなので、以下の文章は読まなくてもよいことになりましたが、記録のために残しておきます。

(追記ここまで)


あらすじ

練習でISUCON9予選のコードにNew Relicエージェントを導入したときは、gojiを使っていて、 mux.HandleFunc でhandlerを登録する形式だったのでちょっと書き換えればすぐ導入できたのですが、echoだとひと工夫必要でした。

そもそも公式のGoエージェントではどうやっているのか、gojiの場合は

newrelic.WrapHandleFuncといった関数を使うことでGoエージェントを有効にできます(使用例のコードを引用)。

   http.HandleFunc(newrelic.WrapHandleFunc(app, "/users", func(w http.ResponseWriter, req *http.Request) {
        txn := newrelic.FromContext(req.Context())
        txn.AddAttribute("customerLevel", "gold")
        io.WriteString(w, "users page")
    }))

gojiの場合はこんな感じで導入できます。goji.io/patを使っていたので、軽いwrapperを噛ませて使っていました。

func wrapHandleFuncGet(path string, f func(w http.ResponseWriter, r *http.Request)) (*pat.Pattern, func(w http.ResponseWriter, r *http.Request)) {
    pathStr, wrapped := newrelic.WrapHandleFunc(newRelicApp, path, f)
    return pat.Get(pathStr), wrapped
}

func wrapHandleFuncPost(path string, f func(w http.ResponseWriter, r *http.Request)) (*pat.Pattern, func(w http.ResponseWriter, r *http.Request)) {
    pathStr, wrapped := newrelic.WrapHandleFunc(newRelicApp, path, f)
    return pat.Post(pathStr), wrapped
}

func main() {
    // (snip)
    mux.HandleFunc(wrapHandleFuncGet("/users/:user_id.json", getUserItems))
    mux.HandleFunc(wrapHandleFuncPost("/buy", postBuy))
    // (snip)
}

echoミドルウェア選定

GitHubecho newrelic というクエリでGo言語のリポジトリに絞って検索したところ、2020/09/13 時点で以下の5つのリポジトリがヒットしました。

エンドポイントごとにレスポンスを返すのにかかった時間を計測するのはどれでもできそうですが、Transactionオブジェクトをcontextで引き回さないと、DBアクセスにかかった時間までは測定できません。github.com/jessie-codes/echo-relic 以外は そのような実装になっています。

github.com/dafiti/echo-middleware は、ライブラリ側でNewRelicエージェントを初期化しており、また初期化に失敗したらpanicするので、エージェントを無効にしてアプリケーションを動かしたいというユースケースには合わなさそうです。

github.com/notyim/echo-middleware-newrelic は、importしたさいに環境変数の情報をもとにNew Relicエージェントを初期化しています。またエージェント初期化処理のエラーハンドリングがライブラリに委ねられています。ログを吐く処理とか環境変数をどうするか、みたいなのは自分でコントロールしたいので使わなさそうです。 runable 変数はどこで使っているのだろう……。

github.com/phacops/echorelic はNew Relicエージェントを渡してミドルウェアを作るかたちになっていてよさそうですが、c.Request().URL.Path をもとにトランザクション名を決めているのはよくなさそうでした。GET /api/chair/:id へのリクエストが :id ごとに散らばることになってしまいます。

github.com/golang-common-packages/monitoring (名前の範囲が広い!!) は、これもライブラリ側でNewRelicエージェントを初期化してpanicしているので、github.com/dafiti/echo-middleware と同様に採用できなさそうです。

いろいろ見てきましたが、どのライブラリも自分のユースケースには合わなさそうです。ISUCON10予選本番では、echoとNew Relicを組み合わせる例をその場で探して出てきたものを試した結果、 github.com/jessie-codes/echo-relic を採用してしまったのでなかなか大変でした。

エンドポイントにかかった時間は計測できたけど、分散トレーシングとか、SQLにかかった時間が取れてない!!! なんでなの!! と言いながらechorelicのコードを読みに行きました。どうもcontextが渡ってない予感がする? echoのミドルウェアを書くのか? と思いつつ echo.WrapMiddleware っていうのを使うとなんか書けそう、ということでガッと試しました。

ISUCON10 予選突破した #isucon - 私が歌川です

作った

  • e.Use(なんとか(app)) ってやるだけでエージェントが有効になってほしい
    • 全てのエンドポイントを計測したいので、エンドポイントごとにwrapするよりミドルウェアにしたほうが早い
  • エージェントの初期化処理はライブラリを使う側で行いたい
    • エージェントの設定を自由に行いたい
    • エラーハンドリングはこっちでやりたい (panicしないでほしい)
  • トランザクションの名前は c.Path() をもとにしたい
    • GET /api/chair/1 ではなく GET /api/chair/:id にしたい
  • できるだけNew Relicの公式ライブラリが提供する仕組みに乗っかりたい

以上の要件を満たすようなechoミドルウェアはなさそう、そしてちょっと実装すれば欲しいものはできそう、ISUCON10本戦でもNew Relicを使うことになるだろう、ということで作りました。go get github.com/utgwkk/echo-newrelic/v3 して今すぐご利用いただけます。ISUCON10予選の感想戦がてらちょっと試してみて、New Relicにデータが送信されていることは確かめました。

github.com