Cloud Functions(Python)のログをCloud Loggingへ連携する

記事タイトルとURLをコピーする

G-gen の杉村です。 Cloud Functions で Python プログラムを動作させる際に、ログをどのように扱い、出力させればよいかについてご紹介します。

Cloud Functions のログ出力

標準出力と標準 logger

Cloud Functions で動作するプログラムが標準出力に文字列を出力すると 自動的に Cloud Logging に記録 されます。

つまり Python プログラムで print するだけで、テキストを Cloud Logging に送信できるのです。

また Python 標準の logging ライブラリを使っても、ログが Cloud Logging に送信されます。

print 文により Cloud Logging に送出されたテキスト

Cloud Logging ライブラリ

しかし本番運用におけるトラブルシューティングなどをスムーズに行うためには、 Cloud Logging エントリに ログレベル を反映したり、 JSON 形式で追加の情報を持たせてそれをもとにフィルタしたりと、 Cloud Logging の強力なフィルタ機能と組み合わせて利用したくなります。

Cloud Logging ビューワに表示されるログレベル

ログレベル一覧

前述の print や logging では Cloud Logging エントリにログレベルを反映することはできません。標準 logging ライブラリでログレベルを設定しても Cloud Logging 上では全て Default ログレベルとして表示されてしまいます。ログレベルを反映するには JSON 形式でログを構造化し、severity というキーを含めることで反映させることができます。

print や標準 logger ではログレベルが全て Default になる

しかし Cloud Functions で動くプログラムから Cloud Logging API Cloud クライアント ライブラリ を利用することで、簡単にログレベルを反映させたり、カスタム属性を追加することもできます。

当記事では Cloud Logging ライブラリを Python で利用する方法をご紹介します。

ライブラリのインストール

pip コマンドで実行環境に google-cloud-logging をインストールします。

Cloud Functions へデプロイした際に実行環境にライブラリが追加されるよう、 requirements.txt にも反映してください。

$ pip install google-cloud-logging
$ pip freeze > requirements.txt

サンプルコード

比較のため、 Cloud Logging ライブラリを用いる場合と用いない場合の2パターンの Cloud Functions 関数を作成します。

なお以下のコードは Cloud Functions の HTTP 関数 として記述していますが、イベントドリブン関数でも基本は同じです。

1. Cloud Logging ライブラリ無し (標準 logger)

#!/usr/bin/env python
 
 
import logging
 
 
# 標準 Logger の設定
logging.basicConfig(
        format = "[%(asctime)s][%(levelname)s] %(message)s",
        level = logging.DEBUG
    )
logger = logging.getLogger()
 
 
def main(request):
 
    logger.critical("This is a CRITICAL log entry.")
    logger.error("This is an ERROR log entry.")
    logger.warning("This is a WARNING log entry.")
    logger.info("This is an INFO log entry.")
    logger.debug("This is a DEBUG log entry.")
 
    return "OK"

2. Cloud Logging ライブラリ使用

#!/usr/bin/env python
 
import logging
 
import google.cloud.logging
 
 
# 標準 Logger の設定
logging.basicConfig(
        format = "[%(asctime)s][%(levelname)s] %(message)s",
        level = logging.DEBUG
    )
logger = logging.getLogger()
 
 
# Cloud Logging ハンドラを logger に接続
logging_client = google.cloud.logging.Client()
logging_client.setup_logging()
 
# setup_logging() するとログレベルが INFO になるので DEBUG に変更
logger.setLevel(logging.DEBUG)
 
 
def main(request):
 
    logger.critical("This is a CRITICAL log entry.")
    logger.error("This is an ERROR log entry.")
    logger.warning("This is a WARNING log entry.")
    logger.info("This is an INFO log entry.")
    logger.debug("This is a DEBUG log entry.")
 
    return "OK"

前者のコードと後者のコードの差は 5 行目と 16 〜 23 行目のみです。

16 〜 23 行目では Cloud Logging のクライアントを生成して標準 logger ライブラリと接続させています。これによりロガーに送出されたログは、全て Cloud Logging に送信されます。

なお setup_logging() を実行する際にログレベルが INFO に変更されるので今回は明示的に DEBUG を指定しています。

実行結果

上記の Python プログラムを Cloud Functions にデプロイし、実行しました。なお実行環境として Cloud Functions (第2世代) で検証しましたが、第1世代でも基本的な挙動は同様です。

1. Cloud Logging ライブラリ無し (標準 logger)

標準 logger

標準 logger では Cloud Logging ログの属性にログレベルが反映されていません。

またプログラム内で指定したフォーマットが解釈 (パース) されず、そのままテキストとして表示されています。

2. Cloud Logging ライブラリ使用

Cloud Logging クライアントライブラリ

Cloud Logging ライブラリを使用した場合、ログエントリの左端に色付きでログレベルが反映されているのが分かります。

また [(時刻)][(ログレベル)] というフォーマットがパースされて省略されていることも分かります。

Cloud Logging と統合されていることにより、ログレベルのほか「実行ファイル名」「ログ送出元の関数名 (main)」「ログが発生したプログラムの行数」などもログに含まれています。

様々な付加情報

これにより、ログレベルや他のロギング情報によるフィルタリングが可能になり、本番運用の負荷軽減に役立つでしょう。

杉村 勇馬 (記事一覧)

執行役員 CTO / クラウドソリューション部 部長

元警察官という経歴を持つ現 IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 12資格、Google Cloud認定資格11資格。X (旧 Twitter) では Google Cloud や AWS のアップデート情報をつぶやいています。