Pub/Sub中のProtocol Buffersメッセージを覗いてみる


デバッグ時などに知っていると便利です。

準備

チュートリアルのメッセージで試しています。

from protocol_example import addressbook_pb2
from google.cloud import pubsub_v1

person = addressbook_pb2.Person()
person.id = 1234
person.name = "John Doe"
person.email = "[email protected]"
phone = person.phones.add()
phone.number = "555-4321"
phone.type = addressbook_pb2.Person.HOME

publisher = pubsub_v1.PublisherClient()
topic_path = publisher.topic_path("プロジェクトid", "トピック名")
publisher.publish(topic_path, person.SerializeToString())

定義ファイルが無い場合

gcloud --format=json pubsub subscriptions pull "サブスクリプション名" | jq -r .[].message.data | base64 -D | protoc --decode_raw                                               
1: "John Doe"
2: 1234
3: "[email protected]"
4 {
  1: "555-4321"
  2: 1
}

定義ファイルがある場合

gcloud --format=json pubsub subscriptions pull "サブスクリプション名"| jq -r .[].message.data | base64 -D | protoc --decode tutorial.Person  protocol_example.pb2
name: "John Doe"
id: 1234
email: "[email protected]"
phones {
  number: "555-4321"
  type: HOME
}

補足

ちょっとややこしいので補足です:

gcloud pubsub subscriptions pull

  • デフォルトではackしないので、安心して使えます
    • ackしたい時は--auto-ack
  • メッセージがあったとしても取れる件数にばらつきがある(一件も取れない時もある)ので注意です
    • "Please note that this command is not guaranteed to return all the messages in your backlog or the maximum specified in the --limit argument. Receiving fewer messages than available occasionally is normal. "
  • formatオプションを指定すると下のようなjson形式で取れます
    • (gcloudの大体のサブコマンドで使えます)
[
  {
    "ackId": "TgQhIT4wPkVTRFAGFixdRkhRNxkIaFEOT14jPzUgKEUQC1MTUVx2E0kQazNcdQdRDRh1fTRwOwlCAQNCWX5VWwk8aH58dAdUDBh7fWh2bFobBgRDW1ar3OiojJOCRB1tNZj6iKJASt7drYV3Zhg9XBJLLD5-PThFQV5AEkw2DURJUytDCypYEQ",
    "message": {
      "data": "CghKb2huIERvZRDSCRoQamRvZUBleGFtcGxlLmNvbSIMCgg1NTUtNDMyMRAB",
      "messageId": "1051190936087668",
      "publishTime": "2020-03-16T23:27:40.736Z"
    }
  }
]

jq

  • ↑のJSONからメッセージの中身を取るために使っています
  • デフォルトでは出力にダブルクオートが付くので、rオプションで外しています

protoc

  • カレントディレクトリの時は良いのですが、相対ディレクトリを参照するにはIオプションで指定します
    • protoc --decode tutorial.Person ../protocol_example.pb2ではなく、protoc --decode tutorial.Person -I=../ protocol_example.pb2
  • パッケージが定義されている時は、そこから指定(tutorial.Person)する必要があります