[{"data":1,"prerenderedAt":871},["ShallowReactive",2],{"content-\u002Fcontents\u002Fpythonlogger":3,"surroundPost-\u002Fcontents\u002Fpythonlogger":862},{"id":4,"title":5,"body":6,"createdAt":850,"description":62,"draft":851,"extension":852,"meta":853,"navigation":78,"path":854,"seo":855,"stem":856,"tags":857,"thumbnail":860,"updatedAt":850,"__hash__":861},"contents\u002Fcontents\u002Fpythonlogger.md","Pythonでログ出力する方法について",{"type":7,"value":8,"toc":844},"minimark",[9,18,21,42,47,53,56,119,122,129,147,154,163,185,195,200,205,212,239,245,303,306,331,334,340,376,379,397,407,410,414,432,435,448,465,471,688,691,727,730,767,774,777,781,785,792,798,801,804,807,840],[10,11,12,13,17],"p",{},"本記事では、Python のログの取り方、つまり",[14,15,16],"code",{},"logging","モジュールの使い方を説明します。",[10,19,20],{},"結論としては、Python で logging モジュールを使ってログをとる場合は以下のことを意識すると良いです。",[22,23,24,35],"ul",{},[25,26,27,30,31,34],"li",{},[14,28,29],{},"import logging","ではなく",[14,32,33],{},"from logging import getLogger","を使う",[25,36,37,38,41],{},"自作の",[14,39,40],{},"logger","取得関数を作り、必要な設定を書いておく",[43,44,46],"h2",{"id":45},"logging-モジュールを使用した-python-のログ出力方法","logging モジュールを使用した Python のログ出力方法",[10,48,49,50,52],{},"早速 Python で最初から使える",[14,51,16],{},"モジュールを試してみます。",[10,54,55],{},"以下のスクリプトを実行します。",[57,58,63],"pre",{"className":59,"code":60,"language":61,"meta":62,"style":62},"language-py shiki shiki-themes github-dark","import logging\n\n\ndef main():\n    logging.info(\"INFO message\")\n\n\nif __name__ == \"__main__\":\n    main()\n","py","",[14,64,65,73,80,85,91,97,102,107,113],{"__ignoreMap":62},[66,67,70],"span",{"class":68,"line":69},"line",1,[66,71,72],{},"import logging\n",[66,74,76],{"class":68,"line":75},2,[66,77,79],{"emptyLinePlaceholder":78},true,"\n",[66,81,83],{"class":68,"line":82},3,[66,84,79],{"emptyLinePlaceholder":78},[66,86,88],{"class":68,"line":87},4,[66,89,90],{},"def main():\n",[66,92,94],{"class":68,"line":93},5,[66,95,96],{},"    logging.info(\"INFO message\")\n",[66,98,100],{"class":68,"line":99},6,[66,101,79],{"emptyLinePlaceholder":78},[66,103,105],{"class":68,"line":104},7,[66,106,79],{"emptyLinePlaceholder":78},[66,108,110],{"class":68,"line":109},8,[66,111,112],{},"if __name__ == \"__main__\":\n",[66,114,116],{"class":68,"line":115},9,[66,117,118],{},"    main()\n",[10,120,121],{},"結果は何も表示されません。",[10,123,124,125,128],{},"以下のように",[14,126,127],{},"warning","にするとメッセージが表示されます。",[57,130,132],{"className":59,"code":131,"language":61,"meta":62,"style":62},"def main():\n    logging.info(\"INFO message\")\n    logging.warning(\"Warning message\")\n",[14,133,134,138,142],{"__ignoreMap":62},[66,135,136],{"class":68,"line":69},[66,137,90],{},[66,139,140],{"class":68,"line":75},[66,141,96],{},[66,143,144],{"class":68,"line":82},[66,145,146],{},"    logging.warning(\"Warning message\")\n",[10,148,149,150,153],{},"表示メッセージは",[14,151,152],{},"WARNING:root:Warning message","となります。",[10,155,156,159,160,162],{},[14,157,158],{},"INFO","のメッセージが表示されないのはデフォルトのログレベルが",[14,161,127],{},"に指定されているからです。",[10,164,165,166,168,169,172,173,172,175,172,178,172,181,184],{},"Python の ",[14,167,16],{}," モジュールでは、重大度ごとにログ出力を切り替えられるようにログレベルが設定されています。\n重大度ごとに",[14,170,171],{},"DEBUG",", ",[14,174,158],{},[14,176,177],{},"WARNING",[14,179,180],{},"ERROR",[14,182,183],{},"CRITICAL","です。",[10,186,187,188,191,192,194],{},"メッセージに含まれる",[14,189,190],{},"root","というのは ",[14,193,16],{}," モジュールが root で実行されたということを暗に意味します。\n（実際にはそうでなくても root で実行されたように見えてしまう）",[10,196,197,199],{},[14,198,16],{},"モジュール周辺の仕組みは本記事の最後に記載した記事が参考になります。",[10,201,202,204],{},[14,203,190],{},"の意味を考える例として、別モジュールの関数を呼び出すケースを試します。",[10,206,207,208,211],{},"以下が",[14,209,210],{},"mod1.py","の中身です。",[57,213,215],{"className":59,"code":214,"language":61,"meta":62,"style":62},"import logging\n\n\ndef test_func():\n    logging.warning(\"warning だよ\")\n",[14,216,217,221,225,229,234],{"__ignoreMap":62},[66,218,219],{"class":68,"line":69},[66,220,72],{},[66,222,223],{"class":68,"line":75},[66,224,79],{"emptyLinePlaceholder":78},[66,226,227],{"class":68,"line":82},[66,228,79],{"emptyLinePlaceholder":78},[66,230,231],{"class":68,"line":87},[66,232,233],{},"def test_func():\n",[66,235,236],{"class":68,"line":93},[66,237,238],{},"    logging.warning(\"warning だよ\")\n",[10,240,241,242,244],{},"そして以下が",[14,243,210],{},"を呼び出す側です。",[57,246,248],{"className":59,"code":247,"language":61,"meta":62,"style":62},"import logging\n\nfrom mod1 import test_func\n\n\ndef main():\n    logging.warning(\"Warning message\")\n    test_func()\n\n\nif __name__ == \"__main__\":\n    main()\n\n",[14,249,250,254,258,263,267,271,275,279,284,288,293,298],{"__ignoreMap":62},[66,251,252],{"class":68,"line":69},[66,253,72],{},[66,255,256],{"class":68,"line":75},[66,257,79],{"emptyLinePlaceholder":78},[66,259,260],{"class":68,"line":82},[66,261,262],{},"from mod1 import test_func\n",[66,264,265],{"class":68,"line":87},[66,266,79],{"emptyLinePlaceholder":78},[66,268,269],{"class":68,"line":93},[66,270,79],{"emptyLinePlaceholder":78},[66,272,273],{"class":68,"line":99},[66,274,90],{},[66,276,277],{"class":68,"line":104},[66,278,146],{},[66,280,281],{"class":68,"line":109},[66,282,283],{},"    test_func()\n",[66,285,286],{"class":68,"line":115},[66,287,79],{"emptyLinePlaceholder":78},[66,289,291],{"class":68,"line":290},10,[66,292,79],{"emptyLinePlaceholder":78},[66,294,296],{"class":68,"line":295},11,[66,297,112],{},[66,299,301],{"class":68,"line":300},12,[66,302,118],{},[10,304,305],{},"このファイルを実行した時の出力は以下のようになります。",[57,307,311],{"className":308,"code":309,"language":310,"meta":62,"style":62},"language-bash shiki shiki-themes github-dark","WARNING:root:Warning message\nWARNING:root:warning だよ\n","bash",[14,312,313,323],{"__ignoreMap":62},[66,314,315,319],{"class":68,"line":69},[66,316,318],{"class":317},"svObZ","WARNING:root:Warning",[66,320,322],{"class":321},"sU2Wk"," message\n",[66,324,325,328],{"class":68,"line":75},[66,326,327],{"class":317},"WARNING:root:warning",[66,329,330],{"class":321}," だよ\n",[10,332,333],{},"この結果からだとログがどのモジュールで吐き出されたのかわかりません。",[10,335,336,337,339],{},"ではどうすればいいのかというと、各モジュールで以下のように ",[14,338,40],{}," を定義します。",[57,341,343],{"className":59,"code":342,"language":61,"meta":62,"style":62},"from logging import getLogger\n\nlogger = getLogger(__name__)\n\n\ndef test_func():\n    logger.warning(\"warning だよ\")\n\n",[14,344,345,350,354,359,363,367,371],{"__ignoreMap":62},[66,346,347],{"class":68,"line":69},[66,348,349],{},"from logging import getLogger\n",[66,351,352],{"class":68,"line":75},[66,353,79],{"emptyLinePlaceholder":78},[66,355,356],{"class":68,"line":82},[66,357,358],{},"logger = getLogger(__name__)\n",[66,360,361],{"class":68,"line":87},[66,362,79],{"emptyLinePlaceholder":78},[66,364,365],{"class":68,"line":93},[66,366,79],{"emptyLinePlaceholder":78},[66,368,369],{"class":68,"line":99},[66,370,233],{},[66,372,373],{"class":68,"line":104},[66,374,375],{},"    logger.warning(\"warning だよ\")\n",[10,377,378],{},"そして先ほどと同じように実行すると以下の出力が得られます。",[57,380,382],{"className":308,"code":381,"language":310,"meta":62,"style":62},"WARNING:root:Warning message\nWARNING:mod1:warning だよ\n",[14,383,384,390],{"__ignoreMap":62},[66,385,386,388],{"class":68,"line":69},[66,387,318],{"class":317},[66,389,322],{"class":321},[66,391,392,395],{"class":68,"line":75},[66,393,394],{"class":317},"WARNING:mod1:warning",[66,396,330],{"class":321},[10,398,399,400,402,403,406],{},"メッセージの",[14,401,190],{},"が",[14,404,405],{},"mod1","に変わりました！",[10,408,409],{},"ただ、これだけではログとしては情報が足りません。もう少し細かい設定を行なっていきます。",[43,411,413],{"id":412},"logger-の細かい設定","logger の細かい設定",[10,415,416,418,419,421,422,425,426,428,429,431],{},[14,417,16],{}," モジュールから生成された ",[14,420,40],{}," には ",[14,423,424],{},"handler"," を設定・追加することができます。\n",[14,427,424],{}," とは ",[14,430,40],{}," から渡されたログメッセージを指定された場所に送るものです。",[10,433,434],{},"ここは具体例を見た方がわかりやすいです。",[10,436,437,438,440,441,443,444,447],{},"以下の内容ができるように",[14,439,40],{},"に",[14,442,424],{},"をセットし、出力を",[14,445,446],{},"formatter","でレイアウトします。",[22,449,450,453,456,459,462],{},[25,451,452],{},"ログレベルの設定",[25,454,455],{},"ログを標準出力で表示",[25,457,458],{},"ログが記録された日時を表示",[25,460,461],{},"ログが書かれた行数表示",[25,463,464],{},"ログのファイルへの書き出し",[10,466,467,468,470],{},"こちらが実際のコードです。ハンドラー等を定義した",[14,469,40],{},"を各 Python ファイルから呼べるようにしてあります。",[57,472,474],{"className":59,"code":473,"language":61,"meta":62,"style":62},"import os\nimport datetime\nfrom logging import getLogger, StreamHandler, FileHandler, Formatter, DEBUG\n\n\ndef get_my_logger(module_name: str):\n\n    # 呼び出したモジュール名がセットされるようにする\n    logger = getLogger(module_name)\n\n    # ログレベルの定義\n    logger.setLevel(DEBUG)\n\n    # 出力されるログの表示内容を定義\n    formatter = Formatter(\n        \"%(asctime)s : %(name)s : %(levelname)s : %(lineno)s : %(message)s\"\n    )\n\n    # 標準出力のhandlerをセット\n    stream_handler = StreamHandler()\n    stream_handler.setLevel(DEBUG)\n    stream_handler.setFormatter(formatter)\n    logger.addHandler(stream_handler)\n\n    # ファイル出力のhandlerをセット\n    logs_dir_name = \"logs\"\n    os.makedirs(logs_dir_name, exist_ok=True)\n    dt_now_jst_aware = datetime.datetime.now(\n        datetime.timezone(datetime.timedelta(hours=9))\n    )\n    file_name = dt_now_jst_aware.strftime(\"%Y%m%d_%H%M%S\") + \".log\"\n    file_path = os.path.join(logs_dir_name, file_name)\n    file_handler = FileHandler(file_path)\n    file_handler.setLevel(DEBUG)\n    file_handler.setFormatter(formatter)\n\n    logger.addHandler(file_handler)\n\n    return logger\n",[14,475,476,481,486,491,495,499,504,508,513,518,522,527,532,537,543,549,555,561,566,572,578,584,590,596,601,607,613,619,625,631,636,642,648,654,660,666,671,677,682],{"__ignoreMap":62},[66,477,478],{"class":68,"line":69},[66,479,480],{},"import os\n",[66,482,483],{"class":68,"line":75},[66,484,485],{},"import datetime\n",[66,487,488],{"class":68,"line":82},[66,489,490],{},"from logging import getLogger, StreamHandler, FileHandler, Formatter, DEBUG\n",[66,492,493],{"class":68,"line":87},[66,494,79],{"emptyLinePlaceholder":78},[66,496,497],{"class":68,"line":93},[66,498,79],{"emptyLinePlaceholder":78},[66,500,501],{"class":68,"line":99},[66,502,503],{},"def get_my_logger(module_name: str):\n",[66,505,506],{"class":68,"line":104},[66,507,79],{"emptyLinePlaceholder":78},[66,509,510],{"class":68,"line":109},[66,511,512],{},"    # 呼び出したモジュール名がセットされるようにする\n",[66,514,515],{"class":68,"line":115},[66,516,517],{},"    logger = getLogger(module_name)\n",[66,519,520],{"class":68,"line":290},[66,521,79],{"emptyLinePlaceholder":78},[66,523,524],{"class":68,"line":295},[66,525,526],{},"    # ログレベルの定義\n",[66,528,529],{"class":68,"line":300},[66,530,531],{},"    logger.setLevel(DEBUG)\n",[66,533,535],{"class":68,"line":534},13,[66,536,79],{"emptyLinePlaceholder":78},[66,538,540],{"class":68,"line":539},14,[66,541,542],{},"    # 出力されるログの表示内容を定義\n",[66,544,546],{"class":68,"line":545},15,[66,547,548],{},"    formatter = Formatter(\n",[66,550,552],{"class":68,"line":551},16,[66,553,554],{},"        \"%(asctime)s : %(name)s : %(levelname)s : %(lineno)s : %(message)s\"\n",[66,556,558],{"class":68,"line":557},17,[66,559,560],{},"    )\n",[66,562,564],{"class":68,"line":563},18,[66,565,79],{"emptyLinePlaceholder":78},[66,567,569],{"class":68,"line":568},19,[66,570,571],{},"    # 標準出力のhandlerをセット\n",[66,573,575],{"class":68,"line":574},20,[66,576,577],{},"    stream_handler = StreamHandler()\n",[66,579,581],{"class":68,"line":580},21,[66,582,583],{},"    stream_handler.setLevel(DEBUG)\n",[66,585,587],{"class":68,"line":586},22,[66,588,589],{},"    stream_handler.setFormatter(formatter)\n",[66,591,593],{"class":68,"line":592},23,[66,594,595],{},"    logger.addHandler(stream_handler)\n",[66,597,599],{"class":68,"line":598},24,[66,600,79],{"emptyLinePlaceholder":78},[66,602,604],{"class":68,"line":603},25,[66,605,606],{},"    # ファイル出力のhandlerをセット\n",[66,608,610],{"class":68,"line":609},26,[66,611,612],{},"    logs_dir_name = \"logs\"\n",[66,614,616],{"class":68,"line":615},27,[66,617,618],{},"    os.makedirs(logs_dir_name, exist_ok=True)\n",[66,620,622],{"class":68,"line":621},28,[66,623,624],{},"    dt_now_jst_aware = datetime.datetime.now(\n",[66,626,628],{"class":68,"line":627},29,[66,629,630],{},"        datetime.timezone(datetime.timedelta(hours=9))\n",[66,632,634],{"class":68,"line":633},30,[66,635,560],{},[66,637,639],{"class":68,"line":638},31,[66,640,641],{},"    file_name = dt_now_jst_aware.strftime(\"%Y%m%d_%H%M%S\") + \".log\"\n",[66,643,645],{"class":68,"line":644},32,[66,646,647],{},"    file_path = os.path.join(logs_dir_name, file_name)\n",[66,649,651],{"class":68,"line":650},33,[66,652,653],{},"    file_handler = FileHandler(file_path)\n",[66,655,657],{"class":68,"line":656},34,[66,658,659],{},"    file_handler.setLevel(DEBUG)\n",[66,661,663],{"class":68,"line":662},35,[66,664,665],{},"    file_handler.setFormatter(formatter)\n",[66,667,669],{"class":68,"line":668},36,[66,670,79],{"emptyLinePlaceholder":78},[66,672,674],{"class":68,"line":673},37,[66,675,676],{},"    logger.addHandler(file_handler)\n",[66,678,680],{"class":68,"line":679},38,[66,681,79],{"emptyLinePlaceholder":78},[66,683,685],{"class":68,"line":684},39,[66,686,687],{},"    return logger\n",[10,689,690],{},"ログを記述するファイルで以下のように呼び出し使用します。",[57,692,694],{"className":59,"code":693,"language":61,"meta":62,"style":62},"from my_logger import get_my_logger\n\nlogger = get_my_logger(__name__)\n\n\ndef test_func():\n    logger.debug(\"debug だよ\")\n",[14,695,696,701,705,710,714,718,722],{"__ignoreMap":62},[66,697,698],{"class":68,"line":69},[66,699,700],{},"from my_logger import get_my_logger\n",[66,702,703],{"class":68,"line":75},[66,704,79],{"emptyLinePlaceholder":78},[66,706,707],{"class":68,"line":82},[66,708,709],{},"logger = get_my_logger(__name__)\n",[66,711,712],{"class":68,"line":87},[66,713,79],{"emptyLinePlaceholder":78},[66,715,716],{"class":68,"line":93},[66,717,79],{"emptyLinePlaceholder":78},[66,719,720],{"class":68,"line":99},[66,721,233],{},[66,723,724],{"class":68,"line":104},[66,725,726],{},"    logger.debug(\"debug だよ\")\n",[10,728,729],{},"こちらが出力です。",[57,731,733],{"className":308,"code":732,"language":310,"meta":62,"style":62},"2022-02-11 17:43:25,961 : mod1 : DEBUG : 7 : debug だよ\n",[14,734,735],{"__ignoreMap":62},[66,736,737,740,743,746,749,751,754,756,760,762,765],{"class":68,"line":69},[66,738,739],{"class":317},"2022-02-11",[66,741,742],{"class":321}," 17:43:25,961",[66,744,745],{"class":321}," :",[66,747,748],{"class":321}," mod1",[66,750,745],{"class":321},[66,752,753],{"class":321}," DEBUG",[66,755,745],{"class":321},[66,757,759],{"class":758},"sDLfK"," 7",[66,761,745],{"class":321},[66,763,764],{"class":321}," debug",[66,766,330],{"class":321},[10,768,769,770,773],{},"そしてこの出力は",[14,771,772],{},"logs\u002F20220211_174325.log","にファイルとして保存されています。",[10,775,776],{},"Jupyter Notebook でも表示されます。",[778,779],"img",{"alt":40,"img-src":780},"\u002Fimg\u002Fpython-logger\u002Flogger.png",[43,782,784],{"id":783},"logger-出力と-print-どっちがいい","logger 出力と print どっちがいい？",[10,786,787,788,791],{},"小規模かつ個人で実験するだけの Python コードであれば",[14,789,790],{},"print","で良いと思います。",[10,793,794,795,797],{},"一方で、規模の大きいコードや会社で使用するコードを書く場合は",[14,796,40],{},"を使った方が良いと感じています。",[10,799,800],{},"会社の場合は何かと説明が必要になるので、時刻やどこまでうまくいってるかの情報が残っている方が何かと便利です。",[43,802,803],{"id":803},"参考",[10,805,806],{},"以下に参考サイトを記載します。\n特に 2, 4 つ目の情報は非常に参考になりました。",[808,809,810,819,826,833],"ol",{},[25,811,812],{},[813,814,818],"a",{"href":815,"rel":816},"https:\u002F\u002Fdocs.python.org\u002Fja\u002F3\u002Fhowto\u002Flogging.html",[817],"nofollow","公式ドキュメント",[25,820,821],{},[813,822,825],{"href":823,"rel":824},"https:\u002F\u002Fts223.hatenablog.com\u002Fentry\u002Fpycon-jp-2021",[817],"\"Logging モジュールではじめるログ出力入門\" で PyCon JP 2021 に登壇した",[25,827,828],{},[813,829,832],{"href":830,"rel":831},"https:\u002F\u002Fqiita.com\u002Famedama\u002Fitems\u002Fb856b2f30c2f38665701",[817],"ログ出力のための print と import logging はやめてほしい",[25,834,835],{},[813,836,839],{"href":837,"rel":838},"https:\u002F\u002Fhackers-high.com\u002Fpython\u002Flogging-overview\u002F",[817],"【Python】仕組みを理解してログ出力を使いこなす",[841,842,843],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}",{"title":62,"searchDepth":75,"depth":75,"links":845},[846,847,848,849],{"id":45,"depth":75,"text":46},{"id":412,"depth":75,"text":413},{"id":783,"depth":75,"text":784},{"id":803,"depth":75,"text":803},"2022-02-05",false,"md",{},"\u002Fcontents\u002Fpythonlogger",{"title":5,"description":62},"contents\u002Fpythonlogger",[858,859],"Python","2022","\u002Fimg\u002Ftwitter-card.png","y5JRhJsuHE3YSAALZ0g_RqDgyq9zP0C9CxlFzdQa1NY",[863,867],{"title":864,"path":865,"stem":866,"children":-1},"Pythonでよく使うものをコピペ用にまとめてみた","\u002Fcontents\u002Fpython-util","contents\u002Fpython-util",{"title":868,"path":869,"stem":870,"children":-1},"【PyTorch】モデルの可視化・保存方法について学ぶ","\u002Fcontents\u002Fpytorch-advanced","contents\u002Fpytorch-advanced",1782863425457]