2022/06/01

Cloud Loggingにサブスレッドで出力したログが出ない件

Cloud Logginについて

GCPでログを扱うなら、Cloud Loggingは避けて通れない道です。適当にログを吐くコードでを埋め込んでおいて、ブラウザを立ち上げてGCPコンソールのログビューアで表示。しかも30日前くらいまで遡って表示可能。

Cloud Loggingのライブラリの使い方に慣れれば、出力するログのフォーマットもかなり自由に弄べます。ほとんどのGCPサービス・言語で利用できますし、使い方も同じです。

こんなに便利なツールがあるなら、避ける理由などありません。それくらいに便利です。


症状

しかしCloud Loggingには、ログがまともに出ない問題があります。具体的には、

  • サブスレッドから出力したログが、ログビューアに表示されない。主にGCEで発生。
  • サブスレッドから出力したログが、ログビューア上では実際より後の時刻のログに交じって出力される。主にGAEで発生。

メインスレッドから出力すると問題ありません。しかしFirestoreのトランザクションなど、仕様書に明記されていないもののこっそりワーカスレッドを生成して処理しているケースでも上記の問題が発生します。時にはCloud BuildのビルドログがGAEアプリの実行ログに混じることも。


現状

これについてネットで調べても特に情報がないなあと思っていたのですが、ついに公式サイトに載っているのを見つけました。

「Java8 ランタイム環境」の「スレッド」の注釈に説明されています。

注: Java スレッド作成 API を使用する場合、Cloud Trace はリクエスト ID を正しく表示しません。Google は現在この問題の解決に取り組んでいます。

なんと、まだ対応中でした。何年も前から発生しているので早く直してほしいですね。

2022/05/21

GoでGCPプロジェクト管理者を識別する

動機

GCPで動作するアプリケーションを作っていると、アプリケーションの管理者=プロジェクトの管理者 であることが多いと思います。開発フェーズか運用フェーズかでそこに割り当てられている人は変わったとしても、この関係は変わりないのが理想と思います。

であれば、プログラムでプロジェクト管理者のアカウントを判断できれば、「アプリケーション管理者のアカウント」をアプリケーションで保持する必要ながなくなって便利です。


プロジェクト管理者のアカウントをコードで取得する手段を探してみたところ、Goで発見しましたので紹介します。


コード

サービスの名称と機能からIdentity and Access Managementあたりかと あたりをつけて探し始めて、たどり着いたのはResource Managerでした。プロジェクト管理者のアカウントを取得するには、以下の様に複数のAPIを経由します。

import ( "context" "os" "strings" "google.golang.org/api/cloudresourcemanager/v1" ) ... // context.Contextを取得 context := context.Background() // Cloud Resource Managerサービスを取得 crmservice, err := cloudresourcemanager.NewService(context) // (1)Resource Managerサービスを取得 if err != nil { // エラー処理 return } // プロジェクトのIAMポリシーを取得 projid := os.Getenv("GOOGLE_CLOUD_PROJECT") // (2)プロジェクトIDを取得 request := new(cloudresourcemanager.GetIamPolicyRequest) iampolicy, err := crmservice.Projects.GetIamPolicy(projid, request).Do() // (3)IAMポリシーを取得 if err != nil { // エラー処理 return } // このプロジェクトの管理者に含まれているか確認 adminuser := false check_end: for _, binding := range iampolicy.Bindings { // (4)各ポリシー for _, member := range binding.Members { // (5)各メンバ if strings.Contains(member, email) { // (6)Eメールアドレスで判断 adminuser = true break check_end } } } // adminuser == tureならプロジェクト管理者

  1.  Cloud Resource Managerサービスを取得します。
  2.  環境変数GOOGLE_CLOUD_PROJECTからプロジェクトIDを取得しています。Cloud Run/Goではこれで取得できましたが、その他のサービスでは同様に取得できるか分かりませんので、確認してください。
  3. プロジェクトのIdentity and Access Managerポリシーを取得します。メソッドチェインの最後のDo()メソッドが実行結果としてPolicyを返してくれます。
  4. Bindingsプロパティがポリシーにバインドされているプリンシパルの配列です。
  5. 各プリンシパルは複数のメンバーを含んでいます。このメンバーには個人アカウントだけではなく、サービスアカウントなども含まれます。
  6. Eメールアドレスでプロジェクト管理者かどうかを判断しています。個人アカウントの場合は先頭に"user:"が付いているので、Eメールアドレスを含んでいるか否かで判断しています。


ライブラリ

今回使ったライブラリのパッケージは以下。

一方でGoogle公式サイトには以下も載っています。

cloud.google.com/go/resourcemanager/apiv2

後者のライブラリは実装されている機能が少なすぎて、今回のように実装できません。というかAPI仕様を見る限り、ほとんど使い物にならないのではないかと思います。

GoのResource Managerに限らず、どのライブラリを使えばいいのか、こんなの見つけたけど使って大丈夫なのかと、迷うことがよくありますが、今回は以上の実装で目的を果たせました。また前者のライブラリは機能も十分そろっていそうなので、その他の用途にも使えると思います。

2022/05/17

vsReversiアップデート

GCPのデモとして用意していた vsReversiをアップデートしました。


アップデート内容は以下のとおりです。

  • ユーザのログインと新規登録を別に
  • SPA対応
  • デザイン変更

ユーザのログインと新規登録を別に

ユーザ認証にはGCPのIdentity Platform(Firebase Authentication)を使用していますが、これには出来合いのUIとして提供されるもの(Firebase UI)も、単体のAPIも、ログインと新規登録の区別がありません。それらが一緒になったサインインがあるのみです。

しかし日本では、ユーザ登録と登録済みユーザのログインが別になっているのをよく見るので、それらしく分けてみました。やってみて出来なくはないのですが、かえって実装は面倒になってしまった印象です。

またEメールで登録する場合は、OAuth(Google/Facebook/Twitter/etc.)に比べて、追加で実装しなければならないのものが多いので、余計面倒です。具体的には、

  • 入力されたEメールアドレスを確認する
  • 入力されたEメールアドレスが間違っていた場合にユーザ登録を解除
  • ユーザがパスワードを忘れた場合のパスワードリセット
  • ユーザがEメールアドレスの変更を希望した場合の対処 (vsReversiでは割愛)
  • さらにこれらのUIのカスタマイズ (vsReversiでは割愛)

Firebase UIではこれらの一部が対応済みなので、簡単に実装したいならそれを使うのが楽です。ただしUIのデザインは簡素なものなので、カスタマイズしたくなります。


SPA対応

Angularを使って一部のページをSingle Page Applicationに対応させました。ログイン/新規登録後のページがそれです。マテリアルデザインは採用していないので それっぽい見た目にはなっていないのですが、ページ遷移が速くなりました。

今までGAE/Java8メインで作っていたのですが、「GAE/Java8でSPA対応に苦戦」に記載したように、これは複数のURIに1つのページを割り当てることができないので、実装の変更が大掛かりになりました。具体的には...

  • HTMLなどスタティックコンテンツをFirebase Hostingに移行してURI割り当てを解決。
  • ajaxリクエストエンドポイントは過去のGAEの実装を流用。ただしCORS(Cross Origin Resource Sharing)に対応。
  • 管理者用のページはCloud Runで管理者の認証を実装。


GCPの初期からあるサービスだけに、GAEは単体でいろいろ必要なものが用意されていることを実感できました。今回は対応できないものが見つかったので、他にいろいろと物色することになりました。それぞれが別のサービスとして名前を持っているので、利用したサービスの数が増えています。


デザイン変更

SPA対応のついでですが、見た目だけの変更です。


CPUの思考ルーチンなどその他は以前のままで、変りありません。