以前、
Python ログ出力 logging iniファイルを使用しない - Oboe吹きプログラマの黙示録
を書いたが、隣接のサブディレクトリから使用する場合、呼出し側をきちんとインポートしないと、
ValueError: attempted relative import beyond top-level package
になる。
例えば、
blue/logger.py
に対して blue と red が隣接、同じ階層ディレクトリであるとき、
red/some.py
から、logger.py をインポートするので、
from ..blue.logger import Logger
と書くが ValueError: attempted relative import beyond top-level package になってしまうことがある。
この場合は、スクリプトがフルパス指定で実行されるのが前提で!
import sys from pathlib import Path sys.path.append('%s' % Path(__file__).parent.parent.resolve()) from blue.logger import Logger
と、__file__を利用する
Linux で実行するとき、うっかり、、
$ python some.py
と書いてしまうとダメだ、ちゃんとフルパスでスクリプトを指定する必要がある。
以前、書いた logger.py も、あまり良くないので改めて書き直す。
# -*- coding: UTF-8 -*- from logging import Formatter, handlers, StreamHandler, getLogger, DEBUG, WARN, INFO import inspect class Logger: def __init__(self, name=__name__): if name=="blue.logger": fsplits = inspect.stack()[1].filename.split('/') name = fsplits[len(fsplits)-1] # ロガー生成 self.logger = getLogger(name) self.logger.setLevel(DEBUG) formatter = Formatter(fmt="%(asctime)s.%(msecs)03d %(levelname)7s %(message)s [%(name)s %(processName)s - %(threadName)s]", datefmt="%Y/%m/%d %H:%M:%S") # 時刻ローテーション handler = handlers.TimedRotatingFileHandler(filename='/var/log/test.log', encoding='UTF-8', when='D', backupCount=7 ) # サイズローテーション ''' handler = handlers.RotatingFileHandler(filename='/var/log/test.log', encoding='UTF-8', maxBytes=1048576, backupCount=3) ''' # ログファイル設定 handler.setLevel(INFO) handler.setFormatter(formatter) self.logger.addHandler(handler) # 標準出力用 設定: DEBUG レベルまで標準出力する sthandler = StreamHandler() sthandler.setLevel(DEBUG) sthandler.setFormatter(formatter) self.logger.addHandler(sthandler) def debug(self, msg): self.logger.debug(msg) def info(self, msg): self.logger.info(msg) def warn(self, msg): self.logger.warning(msg) def error(self, msg, exc_info=False): self.logger.error(msg, exc_info=exc_info) def critical(self, msg): self.logger.critical(msg)
この中の logger.error は、
def error(self, msg, exc_info=False): self.logger.error(msg, exc_info=exc_info)
True 指定でスタックトレースも出るようにしている
Logger生成で引数を省略すれば、呼出し元スクリプト名が %(name) で 出力
import sys from pathlib import Path # sys.path.append('%s' % Path(__file__).parent.parent.resolve()) from ..blue.logger import Logger logger = Logger() logger.error("メッセージ ERROR") logger.warn("メッセージ WARN") logger.info("メッセージ INFO") logger.debug("メッセージ DEBUG")
Logger生成で引数を指定すれば、%(name) は指定した文字列になる
import sys from pathlib import Path # sys.path.append('%s' % Path(__file__).parent.parent.resolve()) from ..blue.logger import Logger logger = Logger('gold') logger.error("メッセージ ERROR") logger.warn("メッセージ WARN") logger.info("メッセージ INFO") logger.debug("メッセージ DEBUG")