Cloud Functions を使っていて、デバッグ時に行番号やファイル名が取得できなくてちょっと困りました。
色々調べましたが、googleのloggingライブラリをラッパーすることで対応しました。
結果
こんな感じになりました。
時刻も日本時間に修正され、行番号も表示されています。
ログレベルの途中制御も可能になっています。
これでデバッグが楽になりそうです。
準備
- google-cloud-logging を導入しておくこと。
- Cloud Functions のデプロイ時に、requirements.txt にも記入しておくこと。
$ pip install google-cloud-logging
requirements.txt
google.cloud.logging==3.2.1
ソースコード
.
├── main.py
├── gclogger.py
└── requirements.txt
main.py
import base64
from gclogger import gclogger,DEBUG,INFO,ERROR,WARNING,CRITICAL
def hello_pubsub(event, context):
"""Triggered from a message on a Cloud Pub/Sub topic.
Args:
event (dict): Event payload.
context (google.cloud.functions.Context): Metadata for the event.
"""
try:
pubsub_message = base64.b64decode(event['data']).decode('utf-8')
print(pubsub_message)
# 1st, you call createLogger function
gclogger.createLogger()
gclogger.debug('debug message',gclogger.location())
gclogger.info("info message",gclogger.location())
gclogger.warning('warning message',gclogger.location())
gclogger.error('error message',gclogger.location())
gclogger.critical('critical message',gclogger.location())
gclogger.exception('exception message',gclogger.location())
print('log level: ERROR')
# if you want to change log level. call setLevel()
gclogger.setLevel(ERROR)
gclogger.debug('debug message',gclogger.location())
gclogger.info("info message",gclogger.location())
gclogger.warning('warning message',gclogger.location())
gclogger.error('error message',gclogger.location())
gclogger.critical('critical message',gclogger.location())
gclogger.exception('exception message',gclogger.location())
gclogger.setLevel(INFO)
print('log level: INFO')
gclogger.debug('debug message',gclogger.location())
gclogger.info("info message",gclogger.location())
gclogger.warning('warning message',gclogger.location())
gclogger.error('error message',gclogger.location())
gclogger.critical('critical message',gclogger.location())
gclogger.exception('exception message',gclogger.location())
except Exception as e:
print(e)
gclogger.py
from logging import DEBUG,INFO,CRITICAL,ERROR,WARNING
class gclogger():
"""
This module for GCP Logging.
Usage:
from gclogger import gclogger,DEBUG,INFO,ERROR,WARNING,CRITICAL
# 1st, you call createLogger function
gclogger.createLogger()
gclogger.debug('debug message',gclogger.location())
gclogger.info("info message",gclogger.location())
gclogger.warning('warning message',gclogger.location())
gclogger.error('error message',gclogger.location())
gclogger.critical('critical message',gclogger.location())
gclogger.exception('exception message',gclogger.location())
print('log level: ERROR')
# if you want to change log level. call setLevel()
gclogger.setLevel(ERROR)
gclogger.debug('debug message',gclogger.location())
gclogger.info("info message",gclogger.location())
gclogger.warning('warning message',gclogger.location())
gclogger.error('error message',gclogger.location())
gclogger.critical('critical message',gclogger.location())
gclogger.exception('exception message',gclogger.location())
gclogger.setLevel(INFO)
print('log level: INFO')
gclogger.debug('debug message',gclogger.location())
gclogger.info("info message",gclogger.location())
gclogger.warning('warning message',gclogger.location())
gclogger.error('error message',gclogger.location())
gclogger.critical('critical message',gclogger.location())
gclogger.exception('exception message',gclogger.location())
"""
__logger = None
@staticmethod
def createLogger(level:int=DEBUG):
"""
Parameters
----------
level : int, optional. please read setLevel() docs
DESCRIPTION. The default is DEBUG.
Returns
-------
None.
"""
from logging import getLogger
from google.cloud.logging import Client
if gclogger.__logger is None:
Client().setup_logging()
gclogger.__logger = getLogger()
gclogger.__logger.setLevel(DEBUG)
return(None)
@staticmethod
def location(depth=0):
"""
get function_name,line_no,file_name
Parameters
----------
depth : TYPE, optional
DESCRIPTION. The default is 0.
Returns
-------
string "[FUNC_NAME] xxx [LINE_NO] xxx [FILE_NAME] xxx"
"""
import inspect
import os
frame = inspect.currentframe().f_back
filename = os.path.basename(frame.f_code.co_filename)
code_name = frame.f_code.co_name
lineno = frame.f_lineno
return(f'\t[FUNC_NAME] {code_name}\t[LINE_NO] {lineno}\t[FILE_NAME] {filename}')
@staticmethod
def getnow(TimeZone:str="Asia/Tokyo", strformat:str="%Y-%m-%d %H:%M:%S.%f %Z"):
"""
Get the current time considering the time zone and return a string according to the specified format
Parameters
----------
TimeZone : string
DESCRIPTION. set timezone
Usage. "Asia/Tokyo", "America/Los_Angeles", ...
strformat : string
DESCRIPTION. set time format
Usage. "%Y/%m/%d" etc
Returns
-------
strformat
"""
from datetime import datetime
from zoneinfo import ZoneInfo
now = datetime.now(ZoneInfo(TimeZone))
return(now.strftime(strformat))
@staticmethod
def setLevel(level:int):
"""
Parameters
----------
level : DEBUG(10),INFO(20),WARNING(30),ERROR(40),CRITICAL(50)
DESCRIPTION. set log level.
Usage. setLevel(DEBUG) # setLevel(10)
Returns
-------
None.
"""
if not level in (DEBUG,INFO,WARNING,ERROR,CRITICAL):
gclogger.__logger.warning('[WARNING]\tlevel is in DEBUG/INFO/WARNING/ERROR/CRITICAL .')
else:
gclogger.__logger.setLevel(level)
return(None)
@staticmethod
def debug(message,location:str=''):
if gclogger.__logger is not None:
gn = gclogger.getnow()
gclogger.__logger.debug(f'{gn}\t[DEBUG]\t{message}{location}')
else:
gclogger.createLogger()
return(None)
@staticmethod
def info(message,location:str=''):
if gclogger.__logger is not None:
gn = gclogger.getnow()
gclogger.__logger.info(f'{gn}\t[INFO]\t{message}{location}')
else:
gclogger.createLogger()
return(None)
@staticmethod
def warning(message,location:str=''):
if gclogger.__logger is not None:
gn = gclogger.getnow()
gclogger.__logger.warning(f'{gn}\t[WARNING]\t{message}{location}')
else:
gclogger.createLogger()
return(None)
@staticmethod
def error(message,location:str=''):
if gclogger.__logger is not None:
gn = gclogger.getnow()
gclogger.__logger.error(f'{gn}\t[ERROR]\t{message}{location}')
else:
gclogger.createLogger()
return(None)
@staticmethod
def critical(message,location:str=''):
if gclogger.__logger is not None:
gn = gclogger.getnow()
gclogger.__logger.critical(f'{gn}\t[CRITICAL]\t{message}{location}')
else:
gclogger.createLogger()
return(None)
@staticmethod
def exception(message,location:str=''):
"""
err() + Error Class Information
Parameters
----------
message : TYPE
DESCRIPTION.
location : string
DESCRIPTION. Do location() in the function you call
ex: gclogger.exception("Oh my God",gclogger.location())
Returns
-------
None.
"""
if gclogger.__logger is not None:
gn = gclogger.getnow()
gclogger.__logger.exception(f'{gn}\t[ERROR]\t{message}{location}\t[EXCEPTION_MSG]')
else:
gclogger.createLogger()
return(None)
参考
pythonで実行中のファイル、関数、行番号を取得する
(Python)Cloud FunctionsからCloud Loggingへのログ連携方法の比較
Cloud Functions ログの作成、表示、処理