Stage 2 プログラムの土台を作る
2-1 ログを設定する
まずはコードの config.py というファイルをご覧ください。
from logging import getLogger, Formatter, StreamHandler, FileHandler, DEBUG, INFO, WARNING, ERROR, CRITICAL
### LOG SET UP
DEFAULT_LOG_FILE_NAME = 'log.txt'
DEFAULT_LOG_FORMAT = Formatter('%(asctime)s - %(levelname)s - logger:%(name)s - %(filename)s - L%(lineno)d - %(funcName)s - %(message)s')
# file handler
DEFAULT_FHANDLER = FileHandler(DEFAULT_LOG_FILE_NAME, mode='w')
DEFAULT_FHANDLER.setFormatter(DEFAULT_LOG_FORMAT)
DEFAULT_FHANDLER.setLevel(DEBUG)
# stream handler
DEFAULT_SHANDLER = StreamHandler()
DEFAULT_SHANDLER.setFormatter(DEFAULT_LOG_FORMAT)
DEFAULT_SHANDLER.setLevel(WARNING)
# set up function
def logger_setup(logger_name='default', level=DEBUG, *, fhandler=None, fhandler_level=DEBUG, filename=DEFAULT_LOG_FILE_NAME, filemode='w', fileformat=DEFAULT_LOG_FORMAT, shandler=None, shandler_level=WARNING, streamformat=DEFAULT_LOG_FORMAT):
logger = getLogger(logger_name)
logger.setLevel(level)
# file handler
fhandler = fhandler or FileHandler(filename, mode=filemode)
fhandler.setLevel(fhandler_level)
fhandler.setFormatter(fileformat)
logger.addHandler(fhandler)
# stream handler
shandler = shandler or StreamHandler()
shandler.setLevel(shandler_level)
shandler.setFormatter(streamformat)
logger.addHandler(shandler)
return logger
### INDEXES
ROW = 0
COL = 1
### SQUARES STATUS
EMPTY = 0
### DIRECTIONS
UP = [-1, 0]
DOWN = [+1, 0]
LEFT = [0, -1]
RIGHT = [0, +1]
### RETURN VALUES
SUCCEEDED = True
FAILED = False
### DEFAULT VALUES
DEFAULT_PROB4 = 1 / 8
DEFAULT_SIZE = 4 # board size = 4 * 4
DEFAULT_GOAL = 2048
MAX_GOAL = 65536
クソなげーなおい
冒頭で logging からいろいろインポートしていますね。
from logging import getLogger, Formatter, StreamHandler, FileHandler, DEBUG, INFO, WARNING, ERROR, CRITICAL
logger と logging の違いを明確にするために、logging という文字を書かなくていいようにしています。その意義についてはこちらの記事で大いに力説されていますので、是非ご覧ください。
~~~~~~~~~~~~~~~
まずはログの設定をします。
### LOG SET UP
DEFAULT_LOG_FILE_NAME = 'log.txt'
DEFAULT_LOG_FORMAT = Formatter('%(asctime)s - %(levelname)s - logger:%(name)s - %(filename)s - L%(lineno)d - %(funcName)s - %(message)s')
# file handler
DEFAULT_FHANDLER = FileHandler(DEFAULT_LOG_FILE_NAME, mode='w')
DEFAULT_FHANDLER.setFormatter(DEFAULT_LOG_FORMAT)
DEFAULT_FHANDLER.setLevel(DEBUG)
# stream handler
DEFAULT_SHANDLER = StreamHandler()
DEFAULT_SHANDLER.setFormatter(DEFAULT_LOG_FORMAT)
DEFAULT_SHANDLER.setLevel(WARNING)
# set up function
def logger_setup(logger_name='default', level=DEBUG, *, fhandler=None, fhandler_level=DEBUG, filename=DEFAULT_LOG_FILE_NAME, filemode='w', fileformat=DEFAULT_LOG_FORMAT, shandler=None, shandler_level=WARNING, streamformat=DEFAULT_LOG_FORMAT):
logger = getLogger(logger_name)
logger.setLevel(level)
# file handler
fhandler = fhandler or FileHandler(filename, mode=filemode)
fhandler.setLevel(fhandler_level)
fhandler.setFormatter(fileformat)
logger.addHandler(fhandler)
# stream handler
shandler = shandler or StreamHandler()
shandler.setLevel(shandler_level)
shandler.setFormatter(streamformat)
logger.addHandler(shandler)
return logger
こんなに長いの何やるんだよ
大したことないですって。見てけばわかりますから。
~~~~~~~~~~~~~~~
はじめにログを出力するデフォルトのファイルの名前、フォーマットを設定しておきます。
### LOG SET UP
DEFAULT_LOG_FILE_NAME = 'log.txt'
DEFAULT_LOG_FORMAT = Formatter('%(asctime)s - %(levelname)s - logger:%(name)s - %(filename)s - L%(lineno)d - %(funcName)s - %(message)s')
次いで各種ハンドラーのデフォルトの値を宣言します。
# file handler
DEFAULT_FHANDLER = FileHandler(DEFAULT_LOG_FILE_NAME, mode='w')
DEFAULT_FHANDLER.setFormatter(DEFAULT_LOG_FORMAT)
DEFAULT_FHANDLER.setLevel(DEBUG)
# stream handler
DEFAULT_SHANDLER = StreamHandler()
DEFAULT_SHANDLER.setFormatter(DEFAULT_LOG_FORMAT)
DEFAULT_SHANDLER.setLevel(WARNING)
今後ロガーは基本的にこのデフォルトに従って出力しますね。
~~~~~~~~~~~~~~~
下に行くと関数がありますよね。
# logger set up function
def logger_setup(logger_name='default', level=DEBUG, *, fhandler=None, fhandler_level=DEBUG, filename=DEFAULT_LOG_FILE_NAME, filemode='w', fileformat=DEFAULT_LOG_FORMAT, shandler=None, shandler_level=WARNING, streamformat=DEFAULT_LOG_FORMAT):
logger = getLogger(logger_name)
logger.setLevel(level)
# file handler
fhandler = fhandler or FileHandler(filename, mode=filemode)
fhandler.setLevel(fhandler_level)
fhandler.setFormatter(fileformat)
logger.addHandler(fhandler)
# stream handler
shandler = shandler or StreamHandler()
shandler.setLevel(shandler_level)
shandler.setFormatter(streamformat)
logger.addHandler(shandler)
return logger
なんでわざわざ関数なんか作んなあかんの?
今後各ファイルでロガーを作ることになるわけですが、いちいち「ロガーを宣言して、ハンドラーを宣言して、ロガーに加えて、...」っていうのはあまりにも面倒。そこで「いっそのことロガーを作る機能を全部まとめちゃおうじゃないか」という魂胆です。楽になりますよ。
~~~~~~~~~~~~~~~
デフォルトの引数を順に見ていきましょう。
内容 | デフォルト | |
---|---|---|
logger_name | 新設するロガーの名前 | 'default' |
level | ロガーのレベル | DEBUG |
fhandler | ロガーのファイルハンドラー | None |
fhandler_level | ファイルハンドラーに記載する最低レベル | DEBUG |
filename | ログを出力するファイルの名前 | DEFAULT_LOG_FILE_NAME |
filemode | ファイルの書き込みモード(新規書き込み 'w' / 上書き 'a') | 'w' |
fileformat | ファイルに記録するフォーマット | DEFAULT_LOG_FORMAT |
shandler | ロガーのストリームハンドラー | None |
shandler_level | ストリームハンドラーで記録する最低レベル | WARNING |
streamformat | ストリームハンドラーで記録するフォーマット | DEFAULT_LOG_FORMAT |
さっぱり意味わかんねぇ...
所々にリンクを隠していますので、わからない言葉に当たったら都度解説をご覧ください。なんならここを飛ばして 2-2 に行ってしまうのもアリです。
引数の途中にアスタリスク * が一人でいるのは、後続の引数をキーワード引数にするためです。
def logger_setup(logger_name='default', level=DEBUG, *, fhandler=None, fhandler_level=DEBUG, filename=DEFAULT_LOG_FILE_NAME, filemode='w', fileformat=DEFAULT_LOG_FORMAT, shandler=None, shandler_level=WARNING, streamformat=DEFAULT_LOG_FORMAT):
実際に引数を入れるときは logger_setup(filemode='a')
のように、キーワードと一緒に書く必要があります。
~~~~~~~~~~~~~~~
まずは getLogger でロガーを取得。getLogger の引数はロガーにつける名前ですから、logger_setup の引数にした logger_name を入れるんですね。
def logger_setup(logger_name='default', level=DEBUG, *, fhandler=None, fhandler_level=DEBUG, filename=DEFAULT_LOG_FILE_NAME, filemode='w', fileformat=DEFAULT_LOG_FORMAT, shandler=None, shandler_level=WARNING, streamformat=DEFAULT_LOG_FORMAT):
logger = getLogger(logger_name)
logger.setLevel(level)
直下で logger に setLevel を使ってレベルを設定しています。
今度はファイルハンドラーの設定です。
# file handler
fhandler = fhandler or FileHandler(filename, mode=filemode)
fhandler.setLevel(fhandler_level)
fhandler.setFormatter(fileformat)
logger.addHandler(fhandler)
もし引数の時点で使うファイルハンドラーが指定されていれば、それをそのまま fhandler に代入します。一方引数に何も入れられていなければ fhandler は None の状態ですから、FileHandler メソッドでファイルハンドラーを新設するという仕組みになっています。
その下でフォーマットを設定します。
fhandler.setLevel(fhandler_level)
fhandler.setFormatter(fileformat)
logger.addHandler(fhandler)
設定が終われば addHandler で logger に適用しましょう。
~~~~~~~~~~~~~~~
ラストはストリームハンドラーを設定しますよ。
ターミナルとかに出力されるやつやろ
よく勉強してらっしゃるじゃないですか。その通りです。
イヤミかクソ
# stream handler
shandler = shandler or StreamHandler()
shandler.setLevel(shandler_level)
shandler.setFormatter(streamformat)
logger.addHandler(shandler)
やることはファイルハンドラーでやったのと同じです。引数でストリームハンドラーが指定されていればそれを使いますし、指定されていなければ shandler は None ですから、StreamHandler メソッドで新設します。
レベルとフォーマットを設定したら、やはり logger に適用しましょう。
shandler.setFormatter(streamformat)
logger.addHandler(shandler)
~~~~~~~~~~~~~~~
これで logger は出来上がりました。この setLogger メソッドを使ってロガーを作りたいわけですから、リターンするのはロガーがいいですね。
logger = setLogger(...) みたいにしたいってことやろ?
その通りです。ということで、メソッドの最後には
return logger
を入れておきます。