Cloud FunctionsでGoogle Cloud Python Loggingライブラリを使ってみる(初心者向け)

Google Cloud FunctionsでGoogle Cloud Python logging library(google-cloud-logging)の v3.0.0を使ってログ出力をする。
2022.03.31

データアナリティクス事業本部、池田です。
少し前にGoogle CloudのLoggingPythonライブラリに関するアップデートがありました。
Getting Started with Google Cloud Logging Python v3.0.0
記事によると、Cloud Functionsなどでログのドロップが起きにくくなったようです。

これまであまりきちんとしたログ実装をしていなかったので、この機会に使い方を調べてみました。

ライブラリをローカルから使ってみる

Google Cloud Python logging libraryは、Google Cloudのサービス上に限らず、 ローカルからでもログを送ることができるようなので、まずローカル(Python 3.7.7)で試してみました。

import google.cloud.logging
client = google.cloud.logging.Client()
client.setup_logging()

import logging
logging.warning("Hello World")

上記の内容のPythonファイルを作成し、
export GOOGLE_APPLICATION_CREDENTIALS="{credentialファイルのパス}"
のように認証情報を環境変数に設定して実行すると、↓Google Cloudプロジェクトへログが送信されていました。

warningの黄色いアイコンになっています。
Cloud Shell からであれば認証情報のexportは不要でした

Cloud FunctionsでのLogging

今回は、Pub/Subに紐づくCloud Functionsを実装し、 print()での出力とライブラリでのログ出力をやってみました。

(以降ではCloud Shell上でのコマンド発行を前提としています。)

Pub/Subトピックの作成

メッセージの送受信のために、 Pub/Sub のトピックを sample_logging_topic という名前で作成しました。

gcloud pubsub topics create sample_logging_topic

print()する関数を作成

比較用に標準のprint()関数で出力をするCloud Functionsの関数を作成してみます。

main.py

import base64
import os
import json

def sample_print_fn(event, context):
    pubsub_message = base64.b64decode(event["data"]).decode("utf-8")
    print(f"pubsub_message: {pubsub_message}")

    print(json.dumps(event))
    print(event)

    print(f"env: {os.getenv('ENV_VAR')}")

    try:
        print("print at try")
        _ = 1 / 0
    except Exception:
        print("print at except")
        raise
    finally:
        print("print at finally")

内容としては、関数のパラメータ( event["data"] )や環境変数( os.getenv('ENV_VAR') )を print()しています。最後にゼロ除算で例外を起こしています。

上記のファイルを以下のコマンドで sample_print_fn という関数名でデプロイします。

gcloud functions deploy sample_print_fn \
--region asia-northeast1 \
--runtime python39 \
--trigger-topic  sample_logging_topic \
--timeout 30 \
--memory 128MB \
--set-env-vars ENV_VAR=環境変数からの値

--entry-point を指定していないので、関数名のsample_print_fnが実行されます。)

ライブラリを利用する関数を作成

ライブラリを使用するパターンのコードが以下です。

main.py

import base64
import os
import json
from logging import getLogger, DEBUG
import google.cloud.logging

logging_client = google.cloud.logging.Client()
logging_client.setup_logging()
logger = getLogger(__name__)
logger.setLevel(DEBUG)

def sample_logging_fn(event, context):
    pubsub_message = base64.b64decode(event["data"]).decode("utf-8")
    logger.info(f"pubsub_message: {pubsub_message}")

    logger.debug(json.dumps(event))
    logger.debug(event)

    logger.warning(f"env: {os.getenv('ENV_VAR')}")

    try:
        logger.info("info at try")
        _ = 1 / 0
    except Exception:
        logger.error("error at except")
        raise
    finally:
        logger.debug("debug at finally")

Python標準のloggingライブラリと連携して使うことが推奨のようです。
ログレベルを設定しない( logger.setLevel(DEBUG) が無い)場合は、info()はログ出力されてdebug()は出力されませんでした。 コンソールのログ エクスプローラなどで参照する時にもフィルタができるので、細かいログレベルで出力してしまって良いかなと思いました。

ライブラリを利用できるように 依存関係を別ファイルに記述 します。

requirements.txt

google.cloud.logging>=3.0.0

あとは、同様に sample_logging_fn という関数名でデプロイします。

gcloud functions deploy sample_logging_fn \
--region asia-northeast1 \
--runtime python39 \
--trigger-topic  sample_logging_topic \
--timeout 30 \
--memory 128MB \
--set-env-vars ENV_VAR=環境変数からの値

メッセージの発行~ログ確認

Pub/Subにメッセージを発行して、関数を動作させてログを確認してみます。
gcloud pubsub topics publish sample_logging_topic --message="pubsubのメッセージ"

↓print()のパターンのログ(Cloud Functionsの「ログ」タブ)。

コンソール上の「重大度」は「デフォルト」として扱われます。

↓ライブラリを使ったパターンのログ。

ログレベルが設定されていることがアイコンからも分かります。

↓ログ エクスプローラで見た場合。

ちなみに logger.debug(json.dumps(event)) でも logger.debug(event) でも、ログ上は違いは見受けられませんでした。

おわりに

ログは奥が深いので、ハンドラなどの使い方にも慣れたらブログにしたいと思います。たぶん。

関連情報/参考にさせていただいたページ