[{"data":1,"prerenderedAt":2477},["ShallowReactive",2],{"\u002Foptimize\u002Fflask-production-logging-setup":3},{"id":4,"title":5,"body":6,"description":2467,"extension":2468,"meta":2469,"navigation":80,"path":2473,"seo":2474,"stem":2475,"__hash__":2476},"content\u002Foptimize\u002Fflask-production-logging-setup.md","Flask Production Logging Setup",{"type":7,"value":8,"toc":2456},"minimark",[9,13,17,22,30,312,315,319,322,326,1550,1553,1640,1643,1668,1675,1678,1712,1715,1770,1773,1791,1798,1801,1847,1850,1865,1868,1885,1892,1895,1912,1915,1932,1939,1942,1967,1971,2057,2061,2064,2106,2109,2143,2146,2207,2210,2244,2247,2277,2290,2294,2360,2367,2371,2391,2395,2403,2411,2423,2431,2442,2446,2452],[10,11,5],"h1",{"id":12},"flask-production-logging-setup",[14,15,16],"p",{},"If you're trying to set up production logging for Flask or you cannot see useful logs after deployment, this guide shows you how to configure logging step-by-step. The goal is to capture Flask app logs, Gunicorn logs, and Nginx logs in predictable locations and verify that they are working.",[18,19,21],"h2",{"id":20},"quick-fix-quick-setup","Quick Fix \u002F Quick Setup",[14,23,24,25,29],{},"Use ",[26,27,28],"code",{},"journald"," for Gunicorn first, then confirm Nginx logs are active. This gives you a stable baseline before adding file-based Flask logging.",[31,32,37],"pre",{"className":33,"code":34,"language":35,"meta":36,"style":36},"language-bash shiki shiki-themes github-light github-dark","sudo mkdir -p \u002Fvar\u002Flog\u002Fmyflaskapp\nsudo chown -R www-data:www-data \u002Fvar\u002Flog\u002Fmyflaskapp\n\ncat \u003C\u003C'EOF' | sudo tee \u002Fetc\u002Fsystemd\u002Fsystem\u002Fmyflaskapp.service\n[Unit]\nDescription=Gunicorn instance for myflaskapp\nAfter=network.target\n\n[Service]\nUser=www-data\nGroup=www-data\nWorkingDirectory=\u002Fsrv\u002Fmyflaskapp\nEnvironment=\"PATH=\u002Fsrv\u002Fmyflaskapp\u002Fvenv\u002Fbin\"\nExecStart=\u002Fsrv\u002Fmyflaskapp\u002Fvenv\u002Fbin\u002Fgunicorn \\\n  --workers 3 \\\n  --bind unix:\u002Frun\u002Fmyflaskapp.sock \\\n  --access-logfile - \\\n  --error-logfile - \\\n  --capture-output \\\n  wsgi:app\nRestart=always\n\n[Install]\nWantedBy=multi-user.target\nEOF\n\nsudo systemctl daemon-reload\nsudo systemctl restart myflaskapp\nsudo journalctl -u myflaskapp -n 100 --no-pager\nsudo tail -n 100 \u002Fvar\u002Flog\u002Fnginx\u002Faccess.log\nsudo tail -n 100 \u002Fvar\u002Flog\u002Fnginx\u002Ferror.log\n","bash","",[26,38,39,59,75,82,107,113,119,125,130,136,142,148,154,160,166,172,178,184,190,196,202,208,213,219,225,231,236,247,260,283,298],{"__ignoreMap":36},[40,41,44,48,52,56],"span",{"class":42,"line":43},"line",1,[40,45,47],{"class":46},"sScJk","sudo",[40,49,51],{"class":50},"sZZnC"," mkdir",[40,53,55],{"class":54},"sj4cs"," -p",[40,57,58],{"class":50}," \u002Fvar\u002Flog\u002Fmyflaskapp\n",[40,60,62,64,67,70,73],{"class":42,"line":61},2,[40,63,47],{"class":46},[40,65,66],{"class":50}," chown",[40,68,69],{"class":54}," -R",[40,71,72],{"class":50}," www-data:www-data",[40,74,58],{"class":50},[40,76,78],{"class":42,"line":77},3,[40,79,81],{"emptyLinePlaceholder":80},true,"\n",[40,83,85,88,92,95,98,101,104],{"class":42,"line":84},4,[40,86,87],{"class":46},"cat",[40,89,91],{"class":90},"szBVR"," \u003C\u003C",[40,93,94],{"class":50},"'EOF'",[40,96,97],{"class":90}," |",[40,99,100],{"class":46}," sudo",[40,102,103],{"class":50}," tee",[40,105,106],{"class":50}," \u002Fetc\u002Fsystemd\u002Fsystem\u002Fmyflaskapp.service\n",[40,108,110],{"class":42,"line":109},5,[40,111,112],{"class":50},"[Unit]\n",[40,114,116],{"class":42,"line":115},6,[40,117,118],{"class":50},"Description=Gunicorn instance for myflaskapp\n",[40,120,122],{"class":42,"line":121},7,[40,123,124],{"class":50},"After=network.target\n",[40,126,128],{"class":42,"line":127},8,[40,129,81],{"emptyLinePlaceholder":80},[40,131,133],{"class":42,"line":132},9,[40,134,135],{"class":50},"[Service]\n",[40,137,139],{"class":42,"line":138},10,[40,140,141],{"class":50},"User=www-data\n",[40,143,145],{"class":42,"line":144},11,[40,146,147],{"class":50},"Group=www-data\n",[40,149,151],{"class":42,"line":150},12,[40,152,153],{"class":50},"WorkingDirectory=\u002Fsrv\u002Fmyflaskapp\n",[40,155,157],{"class":42,"line":156},13,[40,158,159],{"class":50},"Environment=\"PATH=\u002Fsrv\u002Fmyflaskapp\u002Fvenv\u002Fbin\"\n",[40,161,163],{"class":42,"line":162},14,[40,164,165],{"class":50},"ExecStart=\u002Fsrv\u002Fmyflaskapp\u002Fvenv\u002Fbin\u002Fgunicorn \\\n",[40,167,169],{"class":42,"line":168},15,[40,170,171],{"class":50},"  --workers 3 \\\n",[40,173,175],{"class":42,"line":174},16,[40,176,177],{"class":50},"  --bind unix:\u002Frun\u002Fmyflaskapp.sock \\\n",[40,179,181],{"class":42,"line":180},17,[40,182,183],{"class":50},"  --access-logfile - \\\n",[40,185,187],{"class":42,"line":186},18,[40,188,189],{"class":50},"  --error-logfile - \\\n",[40,191,193],{"class":42,"line":192},19,[40,194,195],{"class":50},"  --capture-output \\\n",[40,197,199],{"class":42,"line":198},20,[40,200,201],{"class":50},"  wsgi:app\n",[40,203,205],{"class":42,"line":204},21,[40,206,207],{"class":50},"Restart=always\n",[40,209,211],{"class":42,"line":210},22,[40,212,81],{"emptyLinePlaceholder":80},[40,214,216],{"class":42,"line":215},23,[40,217,218],{"class":50},"[Install]\n",[40,220,222],{"class":42,"line":221},24,[40,223,224],{"class":50},"WantedBy=multi-user.target\n",[40,226,228],{"class":42,"line":227},25,[40,229,230],{"class":50},"EOF\n",[40,232,234],{"class":42,"line":233},26,[40,235,81],{"emptyLinePlaceholder":80},[40,237,239,241,244],{"class":42,"line":238},27,[40,240,47],{"class":46},[40,242,243],{"class":50}," systemctl",[40,245,246],{"class":50}," daemon-reload\n",[40,248,250,252,254,257],{"class":42,"line":249},28,[40,251,47],{"class":46},[40,253,243],{"class":50},[40,255,256],{"class":50}," restart",[40,258,259],{"class":50}," myflaskapp\n",[40,261,263,265,268,271,274,277,280],{"class":42,"line":262},29,[40,264,47],{"class":46},[40,266,267],{"class":50}," journalctl",[40,269,270],{"class":54}," -u",[40,272,273],{"class":50}," myflaskapp",[40,275,276],{"class":54}," -n",[40,278,279],{"class":54}," 100",[40,281,282],{"class":54}," --no-pager\n",[40,284,286,288,291,293,295],{"class":42,"line":285},30,[40,287,47],{"class":46},[40,289,290],{"class":50}," tail",[40,292,276],{"class":54},[40,294,279],{"class":54},[40,296,297],{"class":50}," \u002Fvar\u002Flog\u002Fnginx\u002Faccess.log\n",[40,299,301,303,305,307,309],{"class":42,"line":300},31,[40,302,47],{"class":46},[40,304,290],{"class":50},[40,306,276],{"class":54},[40,308,279],{"class":54},[40,310,311],{"class":50}," \u002Fvar\u002Flog\u002Fnginx\u002Ferror.log\n",[14,313,314],{},"This setup sends Gunicorn access and error output to the systemd journal, which is the fastest stable default on Ubuntu-based VPS deployments. Add structured Flask file logging after this baseline is working.",[18,316,318],{"id":317},"whats-happening","What’s Happening",[14,320,321],{},"In production, Flask logs often disappear because the development server logger is no longer the active process logger. A complete setup usually includes three layers: Flask application logs, Gunicorn runtime logs, and Nginx access\u002Ferror logs. The goal is to make each layer visible, persistent, and easy to inspect during failures.",[18,323,325],{"id":324},"step-by-step-guide","Step-by-Step Guide",[327,328,329,402,698,998,1091,1215,1352,1455,1504,1545],"ol",{},[330,331,332,336,339,340,360,362,363],"li",{},[333,334,335],"strong",{},"Choose a logging strategy",[337,338],"br",{},"Use:",[341,342,343,348,354],"ul",{},[330,344,345,347],{},[26,346,28],{}," for Gunicorn service output",[330,349,350,353],{},[26,351,352],{},"\u002Fvar\u002Flog\u002Fnginx\u002F*.log"," for reverse proxy access and errors",[330,355,356,359],{},[26,357,358],{},"\u002Fvar\u002Flog\u002Fmyflaskapp\u002F"," only if you need dedicated Flask file logs",[337,361],{},"Create the application log directory if needed:",[31,364,366],{"className":33,"code":365,"language":35,"meta":36,"style":36},"sudo mkdir -p \u002Fvar\u002Flog\u002Fmyflaskapp\nsudo chown -R www-data:www-data \u002Fvar\u002Flog\u002Fmyflaskapp\nsudo chmod 755 \u002Fvar\u002Flog\u002Fmyflaskapp\n",[26,367,368,378,390],{"__ignoreMap":36},[40,369,370,372,374,376],{"class":42,"line":43},[40,371,47],{"class":46},[40,373,51],{"class":50},[40,375,55],{"class":54},[40,377,58],{"class":50},[40,379,380,382,384,386,388],{"class":42,"line":61},[40,381,47],{"class":46},[40,383,66],{"class":50},[40,385,69],{"class":54},[40,387,72],{"class":50},[40,389,58],{"class":50},[40,391,392,394,397,400],{"class":42,"line":77},[40,393,47],{"class":46},[40,395,396],{"class":50}," chmod",[40,398,399],{"class":54}," 755",[40,401,58],{"class":50},[330,403,404,407,409,410,412,413],{},[333,405,406],{},"Configure Flask logging early in app startup",[337,408],{},"Initialize logging before serving requests so startup errors and request-time exceptions are captured.",[337,411],{},"Example for a single-file app:",[31,414,418],{"className":415,"code":416,"language":417,"meta":36,"style":36},"language-python shiki shiki-themes github-light github-dark","import logging\nimport os\nfrom logging.handlers import RotatingFileHandler\nfrom flask import Flask\n\napp = Flask(__name__)\n\nlog_dir = \"\u002Fvar\u002Flog\u002Fmyflaskapp\"\nos.makedirs(log_dir, exist_ok=True)\n\nformatter = logging.Formatter(\n    \"[%(asctime)s] %(levelname)s in %(module)s: %(message)s\"\n)\n\nfile_handler = RotatingFileHandler(\n    f\"{log_dir}\u002Fapp.log\",\n    maxBytes=10_485_760,\n    backupCount=5\n)\nfile_handler.setLevel(logging.INFO)\nfile_handler.setFormatter(formatter)\n\nstream_handler = logging.StreamHandler()\nstream_handler.setLevel(logging.INFO)\nstream_handler.setFormatter(formatter)\n\napp.logger.setLevel(logging.INFO)\napp.logger.addHandler(file_handler)\napp.logger.addHandler(stream_handler)\napp.logger.propagate = False\n","python",[26,419,420,429,436,449,461,465,482,486,496,512,516,526,555,559,563,573,596,608,618,622,632,637,641,651,660,665,669,678,683,688],{"__ignoreMap":36},[40,421,422,425],{"class":42,"line":43},[40,423,424],{"class":90},"import",[40,426,428],{"class":427},"sVt8B"," logging\n",[40,430,431,433],{"class":42,"line":61},[40,432,424],{"class":90},[40,434,435],{"class":427}," os\n",[40,437,438,441,444,446],{"class":42,"line":77},[40,439,440],{"class":90},"from",[40,442,443],{"class":427}," logging.handlers ",[40,445,424],{"class":90},[40,447,448],{"class":427}," RotatingFileHandler\n",[40,450,451,453,456,458],{"class":42,"line":84},[40,452,440],{"class":90},[40,454,455],{"class":427}," flask ",[40,457,424],{"class":90},[40,459,460],{"class":427}," Flask\n",[40,462,463],{"class":42,"line":109},[40,464,81],{"emptyLinePlaceholder":80},[40,466,467,470,473,476,479],{"class":42,"line":115},[40,468,469],{"class":427},"app ",[40,471,472],{"class":90},"=",[40,474,475],{"class":427}," Flask(",[40,477,478],{"class":54},"__name__",[40,480,481],{"class":427},")\n",[40,483,484],{"class":42,"line":121},[40,485,81],{"emptyLinePlaceholder":80},[40,487,488,491,493],{"class":42,"line":127},[40,489,490],{"class":427},"log_dir ",[40,492,472],{"class":90},[40,494,495],{"class":50}," \"\u002Fvar\u002Flog\u002Fmyflaskapp\"\n",[40,497,498,501,505,507,510],{"class":42,"line":132},[40,499,500],{"class":427},"os.makedirs(log_dir, ",[40,502,504],{"class":503},"s4XuR","exist_ok",[40,506,472],{"class":90},[40,508,509],{"class":54},"True",[40,511,481],{"class":427},[40,513,514],{"class":42,"line":138},[40,515,81],{"emptyLinePlaceholder":80},[40,517,518,521,523],{"class":42,"line":144},[40,519,520],{"class":427},"formatter ",[40,522,472],{"class":90},[40,524,525],{"class":427}," logging.Formatter(\n",[40,527,528,531,534,537,540,543,546,549,552],{"class":42,"line":150},[40,529,530],{"class":50},"    \"[",[40,532,533],{"class":54},"%(asctime)s",[40,535,536],{"class":50},"] ",[40,538,539],{"class":54},"%(levelname)s",[40,541,542],{"class":50}," in ",[40,544,545],{"class":54},"%(module)s",[40,547,548],{"class":50},": ",[40,550,551],{"class":54},"%(message)s",[40,553,554],{"class":50},"\"\n",[40,556,557],{"class":42,"line":156},[40,558,481],{"class":427},[40,560,561],{"class":42,"line":162},[40,562,81],{"emptyLinePlaceholder":80},[40,564,565,568,570],{"class":42,"line":168},[40,566,567],{"class":427},"file_handler ",[40,569,472],{"class":90},[40,571,572],{"class":427}," RotatingFileHandler(\n",[40,574,575,578,581,584,587,590,593],{"class":42,"line":174},[40,576,577],{"class":90},"    f",[40,579,580],{"class":50},"\"",[40,582,583],{"class":54},"{",[40,585,586],{"class":427},"log_dir",[40,588,589],{"class":54},"}",[40,591,592],{"class":50},"\u002Fapp.log\"",[40,594,595],{"class":427},",\n",[40,597,598,601,603,606],{"class":42,"line":180},[40,599,600],{"class":503},"    maxBytes",[40,602,472],{"class":90},[40,604,605],{"class":54},"10_485_760",[40,607,595],{"class":427},[40,609,610,613,615],{"class":42,"line":186},[40,611,612],{"class":503},"    backupCount",[40,614,472],{"class":90},[40,616,617],{"class":54},"5\n",[40,619,620],{"class":42,"line":192},[40,621,481],{"class":427},[40,623,624,627,630],{"class":42,"line":198},[40,625,626],{"class":427},"file_handler.setLevel(logging.",[40,628,629],{"class":54},"INFO",[40,631,481],{"class":427},[40,633,634],{"class":42,"line":204},[40,635,636],{"class":427},"file_handler.setFormatter(formatter)\n",[40,638,639],{"class":42,"line":210},[40,640,81],{"emptyLinePlaceholder":80},[40,642,643,646,648],{"class":42,"line":215},[40,644,645],{"class":427},"stream_handler ",[40,647,472],{"class":90},[40,649,650],{"class":427}," logging.StreamHandler()\n",[40,652,653,656,658],{"class":42,"line":221},[40,654,655],{"class":427},"stream_handler.setLevel(logging.",[40,657,629],{"class":54},[40,659,481],{"class":427},[40,661,662],{"class":42,"line":227},[40,663,664],{"class":427},"stream_handler.setFormatter(formatter)\n",[40,666,667],{"class":42,"line":233},[40,668,81],{"emptyLinePlaceholder":80},[40,670,671,674,676],{"class":42,"line":238},[40,672,673],{"class":427},"app.logger.setLevel(logging.",[40,675,629],{"class":54},[40,677,481],{"class":427},[40,679,680],{"class":42,"line":249},[40,681,682],{"class":427},"app.logger.addHandler(file_handler)\n",[40,684,685],{"class":42,"line":262},[40,686,687],{"class":427},"app.logger.addHandler(stream_handler)\n",[40,689,690,693,695],{"class":42,"line":285},[40,691,692],{"class":427},"app.logger.propagate ",[40,694,472],{"class":90},[40,696,697],{"class":54}," False\n",[330,699,700,703,705,706,709,710],{},[333,701,702],{},"Avoid duplicate handlers in app factory setups",[337,704],{},"If you use ",[26,707,708],{},"create_app()",", attach handlers once.",[31,711,713],{"className":415,"code":712,"language":417,"meta":36,"style":36},"import logging\nimport os\nfrom logging.handlers import RotatingFileHandler\nfrom flask import Flask\n\ndef create_app():\n    app = Flask(__name__)\n\n    log_dir = \"\u002Fvar\u002Flog\u002Fmyflaskapp\"\n    os.makedirs(log_dir, exist_ok=True)\n\n    formatter = logging.Formatter(\n        \"[%(asctime)s] %(levelname)s in %(module)s: %(message)s\"\n    )\n\n    file_handler = RotatingFileHandler(\n        f\"{log_dir}\u002Fapp.log\",\n        maxBytes=10_485_760,\n        backupCount=5\n    )\n    file_handler.setLevel(logging.INFO)\n    file_handler.setFormatter(formatter)\n\n    stream_handler = logging.StreamHandler()\n    stream_handler.setLevel(logging.INFO)\n    stream_handler.setFormatter(formatter)\n\n    app.logger.setLevel(logging.INFO)\n\n    if not app.logger.handlers:\n        app.logger.addHandler(file_handler)\n        app.logger.addHandler(stream_handler)\n\n    app.logger.propagate = False\n    return app\n",[26,714,715,721,727,737,747,751,762,775,779,788,801,805,814,835,840,844,853,870,881,890,894,903,908,912,921,930,935,939,948,952,963,968,974,979,989],{"__ignoreMap":36},[40,716,717,719],{"class":42,"line":43},[40,718,424],{"class":90},[40,720,428],{"class":427},[40,722,723,725],{"class":42,"line":61},[40,724,424],{"class":90},[40,726,435],{"class":427},[40,728,729,731,733,735],{"class":42,"line":77},[40,730,440],{"class":90},[40,732,443],{"class":427},[40,734,424],{"class":90},[40,736,448],{"class":427},[40,738,739,741,743,745],{"class":42,"line":84},[40,740,440],{"class":90},[40,742,455],{"class":427},[40,744,424],{"class":90},[40,746,460],{"class":427},[40,748,749],{"class":42,"line":109},[40,750,81],{"emptyLinePlaceholder":80},[40,752,753,756,759],{"class":42,"line":115},[40,754,755],{"class":90},"def",[40,757,758],{"class":46}," create_app",[40,760,761],{"class":427},"():\n",[40,763,764,767,769,771,773],{"class":42,"line":121},[40,765,766],{"class":427},"    app ",[40,768,472],{"class":90},[40,770,475],{"class":427},[40,772,478],{"class":54},[40,774,481],{"class":427},[40,776,777],{"class":42,"line":127},[40,778,81],{"emptyLinePlaceholder":80},[40,780,781,784,786],{"class":42,"line":132},[40,782,783],{"class":427},"    log_dir ",[40,785,472],{"class":90},[40,787,495],{"class":50},[40,789,790,793,795,797,799],{"class":42,"line":138},[40,791,792],{"class":427},"    os.makedirs(log_dir, ",[40,794,504],{"class":503},[40,796,472],{"class":90},[40,798,509],{"class":54},[40,800,481],{"class":427},[40,802,803],{"class":42,"line":144},[40,804,81],{"emptyLinePlaceholder":80},[40,806,807,810,812],{"class":42,"line":150},[40,808,809],{"class":427},"    formatter ",[40,811,472],{"class":90},[40,813,525],{"class":427},[40,815,816,819,821,823,825,827,829,831,833],{"class":42,"line":156},[40,817,818],{"class":50},"        \"[",[40,820,533],{"class":54},[40,822,536],{"class":50},[40,824,539],{"class":54},[40,826,542],{"class":50},[40,828,545],{"class":54},[40,830,548],{"class":50},[40,832,551],{"class":54},[40,834,554],{"class":50},[40,836,837],{"class":42,"line":162},[40,838,839],{"class":427},"    )\n",[40,841,842],{"class":42,"line":168},[40,843,81],{"emptyLinePlaceholder":80},[40,845,846,849,851],{"class":42,"line":174},[40,847,848],{"class":427},"    file_handler ",[40,850,472],{"class":90},[40,852,572],{"class":427},[40,854,855,858,860,862,864,866,868],{"class":42,"line":180},[40,856,857],{"class":90},"        f",[40,859,580],{"class":50},[40,861,583],{"class":54},[40,863,586],{"class":427},[40,865,589],{"class":54},[40,867,592],{"class":50},[40,869,595],{"class":427},[40,871,872,875,877,879],{"class":42,"line":186},[40,873,874],{"class":503},"        maxBytes",[40,876,472],{"class":90},[40,878,605],{"class":54},[40,880,595],{"class":427},[40,882,883,886,888],{"class":42,"line":192},[40,884,885],{"class":503},"        backupCount",[40,887,472],{"class":90},[40,889,617],{"class":54},[40,891,892],{"class":42,"line":198},[40,893,839],{"class":427},[40,895,896,899,901],{"class":42,"line":204},[40,897,898],{"class":427},"    file_handler.setLevel(logging.",[40,900,629],{"class":54},[40,902,481],{"class":427},[40,904,905],{"class":42,"line":210},[40,906,907],{"class":427},"    file_handler.setFormatter(formatter)\n",[40,909,910],{"class":42,"line":215},[40,911,81],{"emptyLinePlaceholder":80},[40,913,914,917,919],{"class":42,"line":221},[40,915,916],{"class":427},"    stream_handler ",[40,918,472],{"class":90},[40,920,650],{"class":427},[40,922,923,926,928],{"class":42,"line":227},[40,924,925],{"class":427},"    stream_handler.setLevel(logging.",[40,927,629],{"class":54},[40,929,481],{"class":427},[40,931,932],{"class":42,"line":233},[40,933,934],{"class":427},"    stream_handler.setFormatter(formatter)\n",[40,936,937],{"class":42,"line":238},[40,938,81],{"emptyLinePlaceholder":80},[40,940,941,944,946],{"class":42,"line":249},[40,942,943],{"class":427},"    app.logger.setLevel(logging.",[40,945,629],{"class":54},[40,947,481],{"class":427},[40,949,950],{"class":42,"line":262},[40,951,81],{"emptyLinePlaceholder":80},[40,953,954,957,960],{"class":42,"line":285},[40,955,956],{"class":90},"    if",[40,958,959],{"class":90}," not",[40,961,962],{"class":427}," app.logger.handlers:\n",[40,964,965],{"class":42,"line":300},[40,966,967],{"class":427},"        app.logger.addHandler(file_handler)\n",[40,969,971],{"class":42,"line":970},32,[40,972,973],{"class":427},"        app.logger.addHandler(stream_handler)\n",[40,975,977],{"class":42,"line":976},33,[40,978,81],{"emptyLinePlaceholder":80},[40,980,982,985,987],{"class":42,"line":981},34,[40,983,984],{"class":427},"    app.logger.propagate ",[40,986,472],{"class":90},[40,988,697],{"class":54},[40,990,992,995],{"class":42,"line":991},35,[40,993,994],{"class":90},"    return",[40,996,997],{"class":427}," app\n",[330,999,1000,1003,1005,1006],{},[333,1001,1002],{},"Log unhandled exceptions with context",[337,1004],{},"Add an error handler so request path and method are included.",[31,1007,1009],{"className":415,"code":1008,"language":417,"meta":36,"style":36},"from flask import request\n\n@app.errorhandler(Exception)\ndef handle_exception(e):\n    app.logger.exception(\n        \"Unhandled exception on %s %s\",\n        request.method,\n        request.path\n    )\n    raise e\n",[26,1010,1011,1022,1026,1039,1049,1054,1069,1074,1079,1083],{"__ignoreMap":36},[40,1012,1013,1015,1017,1019],{"class":42,"line":43},[40,1014,440],{"class":90},[40,1016,455],{"class":427},[40,1018,424],{"class":90},[40,1020,1021],{"class":427}," request\n",[40,1023,1024],{"class":42,"line":61},[40,1025,81],{"emptyLinePlaceholder":80},[40,1027,1028,1031,1034,1037],{"class":42,"line":77},[40,1029,1030],{"class":46},"@app.errorhandler",[40,1032,1033],{"class":427},"(",[40,1035,1036],{"class":54},"Exception",[40,1038,481],{"class":427},[40,1040,1041,1043,1046],{"class":42,"line":84},[40,1042,755],{"class":90},[40,1044,1045],{"class":46}," handle_exception",[40,1047,1048],{"class":427},"(e):\n",[40,1050,1051],{"class":42,"line":109},[40,1052,1053],{"class":427},"    app.logger.exception(\n",[40,1055,1056,1059,1062,1065,1067],{"class":42,"line":115},[40,1057,1058],{"class":50},"        \"Unhandled exception on ",[40,1060,1061],{"class":54},"%s",[40,1063,1064],{"class":54}," %s",[40,1066,580],{"class":50},[40,1068,595],{"class":427},[40,1070,1071],{"class":42,"line":121},[40,1072,1073],{"class":427},"        request.method,\n",[40,1075,1076],{"class":42,"line":127},[40,1077,1078],{"class":427},"        request.path\n",[40,1080,1081],{"class":42,"line":132},[40,1082,839],{"class":427},[40,1084,1085,1088],{"class":42,"line":138},[40,1086,1087],{"class":90},"    raise",[40,1089,1090],{"class":427}," e\n",[330,1092,1093,1096,1098,1099,1101,1102,1104,1105,1168,1170,1171],{},[333,1094,1095],{},"Configure Gunicorn to emit logs",[337,1097],{},"The most reliable baseline is stdout\u002Fstderr into ",[26,1100,28],{},".",[337,1103],{},"If using command flags:",[31,1106,1108],{"className":33,"code":1107,"language":35,"meta":36,"style":36},"\u002Fsrv\u002Fmyflaskapp\u002Fvenv\u002Fbin\u002Fgunicorn \\\n  --workers 3 \\\n  --bind unix:\u002Frun\u002Fmyflaskapp.sock \\\n  --access-logfile - \\\n  --error-logfile - \\\n  --capture-output \\\n  wsgi:app\n",[26,1109,1110,1118,1128,1138,1148,1157,1164],{"__ignoreMap":36},[40,1111,1112,1115],{"class":42,"line":43},[40,1113,1114],{"class":46},"\u002Fsrv\u002Fmyflaskapp\u002Fvenv\u002Fbin\u002Fgunicorn",[40,1116,1117],{"class":54}," \\\n",[40,1119,1120,1123,1126],{"class":42,"line":61},[40,1121,1122],{"class":54},"  --workers",[40,1124,1125],{"class":54}," 3",[40,1127,1117],{"class":54},[40,1129,1130,1133,1136],{"class":42,"line":77},[40,1131,1132],{"class":54},"  --bind",[40,1134,1135],{"class":50}," unix:\u002Frun\u002Fmyflaskapp.sock",[40,1137,1117],{"class":54},[40,1139,1140,1143,1146],{"class":42,"line":84},[40,1141,1142],{"class":54},"  --access-logfile",[40,1144,1145],{"class":50}," -",[40,1147,1117],{"class":54},[40,1149,1150,1153,1155],{"class":42,"line":109},[40,1151,1152],{"class":54},"  --error-logfile",[40,1154,1145],{"class":50},[40,1156,1117],{"class":54},[40,1158,1159,1162],{"class":42,"line":115},[40,1160,1161],{"class":54},"  --capture-output",[40,1163,1117],{"class":54},[40,1165,1166],{"class":42,"line":121},[40,1167,201],{"class":50},[337,1169],{},"If using a Gunicorn config file:",[31,1172,1174],{"className":415,"code":1173,"language":417,"meta":36,"style":36},"accesslog = \"-\"\nerrorlog = \"-\"\ncapture_output = True\nloglevel = \"info\"\n",[26,1175,1176,1186,1195,1205],{"__ignoreMap":36},[40,1177,1178,1181,1183],{"class":42,"line":43},[40,1179,1180],{"class":427},"accesslog ",[40,1182,472],{"class":90},[40,1184,1185],{"class":50}," \"-\"\n",[40,1187,1188,1191,1193],{"class":42,"line":61},[40,1189,1190],{"class":427},"errorlog ",[40,1192,472],{"class":90},[40,1194,1185],{"class":50},[40,1196,1197,1200,1202],{"class":42,"line":77},[40,1198,1199],{"class":427},"capture_output ",[40,1201,472],{"class":90},[40,1203,1204],{"class":54}," True\n",[40,1206,1207,1210,1212],{"class":42,"line":84},[40,1208,1209],{"class":427},"loglevel ",[40,1211,472],{"class":90},[40,1213,1214],{"class":50}," \"info\"\n",[330,1216,1217,1220,1222,1223,1315,1317,1318],{},[333,1218,1219],{},"Update the systemd service",[337,1221],{},"Define a production-safe service unit:",[31,1224,1228],{"className":1225,"code":1226,"language":1227,"meta":36,"style":36},"language-ini shiki shiki-themes github-light github-dark","[Unit]\nDescription=Gunicorn instance for myflaskapp\nAfter=network.target\n\n[Service]\nUser=www-data\nGroup=www-data\nWorkingDirectory=\u002Fsrv\u002Fmyflaskapp\nEnvironment=\"PATH=\u002Fsrv\u002Fmyflaskapp\u002Fvenv\u002Fbin\"\nExecStart=\u002Fsrv\u002Fmyflaskapp\u002Fvenv\u002Fbin\u002Fgunicorn \\\n  --workers 3 \\\n  --bind unix:\u002Frun\u002Fmyflaskapp.sock \\\n  --access-logfile - \\\n  --error-logfile - \\\n  --capture-output \\\n  wsgi:app\nRestart=always\nRestartSec=3\n\n[Install]\nWantedBy=multi-user.target\n","ini",[26,1229,1230,1234,1238,1242,1246,1250,1254,1258,1262,1266,1270,1274,1278,1282,1286,1290,1294,1298,1303,1307,1311],{"__ignoreMap":36},[40,1231,1232],{"class":42,"line":43},[40,1233,112],{},[40,1235,1236],{"class":42,"line":61},[40,1237,118],{},[40,1239,1240],{"class":42,"line":77},[40,1241,124],{},[40,1243,1244],{"class":42,"line":84},[40,1245,81],{"emptyLinePlaceholder":80},[40,1247,1248],{"class":42,"line":109},[40,1249,135],{},[40,1251,1252],{"class":42,"line":115},[40,1253,141],{},[40,1255,1256],{"class":42,"line":121},[40,1257,147],{},[40,1259,1260],{"class":42,"line":127},[40,1261,153],{},[40,1263,1264],{"class":42,"line":132},[40,1265,159],{},[40,1267,1268],{"class":42,"line":138},[40,1269,165],{},[40,1271,1272],{"class":42,"line":144},[40,1273,171],{},[40,1275,1276],{"class":42,"line":150},[40,1277,177],{},[40,1279,1280],{"class":42,"line":156},[40,1281,183],{},[40,1283,1284],{"class":42,"line":162},[40,1285,189],{},[40,1287,1288],{"class":42,"line":168},[40,1289,195],{},[40,1291,1292],{"class":42,"line":174},[40,1293,201],{},[40,1295,1296],{"class":42,"line":180},[40,1297,207],{},[40,1299,1300],{"class":42,"line":186},[40,1301,1302],{},"RestartSec=3\n",[40,1304,1305],{"class":42,"line":192},[40,1306,81],{"emptyLinePlaceholder":80},[40,1308,1309],{"class":42,"line":198},[40,1310,218],{},[40,1312,1313],{"class":42,"line":204},[40,1314,224],{},[337,1316],{},"Reload and restart:",[31,1319,1321],{"className":33,"code":1320,"language":35,"meta":36,"style":36},"sudo systemctl daemon-reload\nsudo systemctl restart myflaskapp\nsudo systemctl status myflaskapp\n",[26,1322,1323,1331,1341],{"__ignoreMap":36},[40,1324,1325,1327,1329],{"class":42,"line":43},[40,1326,47],{"class":46},[40,1328,243],{"class":50},[40,1330,246],{"class":50},[40,1332,1333,1335,1337,1339],{"class":42,"line":61},[40,1334,47],{"class":46},[40,1336,243],{"class":50},[40,1338,256],{"class":50},[40,1340,259],{"class":50},[40,1342,1343,1345,1347,1350],{"class":42,"line":77},[40,1344,47],{"class":46},[40,1346,243],{"class":50},[40,1348,1349],{"class":50}," status",[40,1351,259],{"class":50},[330,1353,1354,1357,1359,1360,1425,1427,1428],{},[333,1355,1356],{},"Enable Nginx access and error logging",[337,1358],{},"Make sure the active server block writes to known files.",[31,1361,1365],{"className":1362,"code":1363,"language":1364,"meta":36,"style":36},"language-nginx shiki shiki-themes github-light github-dark","server {\n    listen 80;\n    server_name example.com;\n\n    access_log \u002Fvar\u002Flog\u002Fnginx\u002Fmyflaskapp_access.log;\n    error_log \u002Fvar\u002Flog\u002Fnginx\u002Fmyflaskapp_error.log warn;\n\n    location \u002F {\n        include proxy_params;\n        proxy_pass http:\u002F\u002Funix:\u002Frun\u002Fmyflaskapp.sock;\n    }\n}\n","nginx",[26,1366,1367,1372,1377,1382,1386,1391,1396,1400,1405,1410,1415,1420],{"__ignoreMap":36},[40,1368,1369],{"class":42,"line":43},[40,1370,1371],{},"server {\n",[40,1373,1374],{"class":42,"line":61},[40,1375,1376],{},"    listen 80;\n",[40,1378,1379],{"class":42,"line":77},[40,1380,1381],{},"    server_name example.com;\n",[40,1383,1384],{"class":42,"line":84},[40,1385,81],{"emptyLinePlaceholder":80},[40,1387,1388],{"class":42,"line":109},[40,1389,1390],{},"    access_log \u002Fvar\u002Flog\u002Fnginx\u002Fmyflaskapp_access.log;\n",[40,1392,1393],{"class":42,"line":115},[40,1394,1395],{},"    error_log \u002Fvar\u002Flog\u002Fnginx\u002Fmyflaskapp_error.log warn;\n",[40,1397,1398],{"class":42,"line":121},[40,1399,81],{"emptyLinePlaceholder":80},[40,1401,1402],{"class":42,"line":127},[40,1403,1404],{},"    location \u002F {\n",[40,1406,1407],{"class":42,"line":132},[40,1408,1409],{},"        include proxy_params;\n",[40,1411,1412],{"class":42,"line":138},[40,1413,1414],{},"        proxy_pass http:\u002F\u002Funix:\u002Frun\u002Fmyflaskapp.sock;\n",[40,1416,1417],{"class":42,"line":144},[40,1418,1419],{},"    }\n",[40,1421,1422],{"class":42,"line":150},[40,1423,1424],{},"}\n",[337,1426],{},"Validate and reload:",[31,1429,1431],{"className":33,"code":1430,"language":35,"meta":36,"style":36},"sudo nginx -t\nsudo systemctl reload nginx\n",[26,1432,1433,1443],{"__ignoreMap":36},[40,1434,1435,1437,1440],{"class":42,"line":43},[40,1436,47],{"class":46},[40,1438,1439],{"class":50}," nginx",[40,1441,1442],{"class":54}," -t\n",[40,1444,1445,1447,1449,1452],{"class":42,"line":61},[40,1446,47],{"class":46},[40,1448,243],{"class":50},[40,1450,1451],{"class":50}," reload",[40,1453,1454],{"class":50}," nginx\n",[330,1456,1457,1460,1462,1463,1466,1467],{},[333,1458,1459],{},"Check file permissions for Flask file logging",[337,1461],{},"If Flask writes directly to ",[26,1464,1465],{},"\u002Fvar\u002Flog\u002Fmyflaskapp",", the service user must own or be allowed to write there.",[31,1468,1470],{"className":33,"code":1469,"language":35,"meta":36,"style":36},"sudo chown -R www-data:www-data \u002Fvar\u002Flog\u002Fmyflaskapp\nsudo chmod 755 \u002Fvar\u002Flog\u002Fmyflaskapp\nls -lah \u002Fvar\u002Flog\u002Fmyflaskapp\n",[26,1471,1472,1484,1494],{"__ignoreMap":36},[40,1473,1474,1476,1478,1480,1482],{"class":42,"line":43},[40,1475,47],{"class":46},[40,1477,66],{"class":50},[40,1479,69],{"class":54},[40,1481,72],{"class":50},[40,1483,58],{"class":50},[40,1485,1486,1488,1490,1492],{"class":42,"line":61},[40,1487,47],{"class":46},[40,1489,396],{"class":50},[40,1491,399],{"class":54},[40,1493,58],{"class":50},[40,1495,1496,1499,1502],{"class":42,"line":77},[40,1497,1498],{"class":46},"ls",[40,1500,1501],{"class":54}," -lah",[40,1503,58],{"class":50},[330,1505,1506,1509,1511,1512],{},[333,1507,1508],{},"Restart services in the correct order",[337,1510],{},"Apply changes and validate:",[31,1513,1515],{"className":33,"code":1514,"language":35,"meta":36,"style":36},"sudo systemctl restart myflaskapp\nsudo nginx -t\nsudo systemctl reload nginx\n",[26,1516,1517,1527,1535],{"__ignoreMap":36},[40,1518,1519,1521,1523,1525],{"class":42,"line":43},[40,1520,47],{"class":46},[40,1522,243],{"class":50},[40,1524,256],{"class":50},[40,1526,259],{"class":50},[40,1528,1529,1531,1533],{"class":42,"line":61},[40,1530,47],{"class":46},[40,1532,1439],{"class":50},[40,1534,1442],{"class":54},[40,1536,1537,1539,1541,1543],{"class":42,"line":77},[40,1538,47],{"class":46},[40,1540,243],{"class":50},[40,1542,1451],{"class":50},[40,1544,1454],{"class":50},[330,1546,1547],{},[333,1548,1549],{},"Trigger test log events",[14,1551,1552],{},"Add a temporary route:",[31,1554,1556],{"className":415,"code":1555,"language":417,"meta":36,"style":36},"@app.route(\"\u002Flog-test\")\ndef log_test():\n    app.logger.info(\"Log test endpoint hit\")\n    return \"ok\", 200\n\n@app.route(\"\u002Flog-error\")\ndef log_error():\n    raise RuntimeError(\"Intentional logging test error\")\n",[26,1557,1558,1570,1579,1589,1602,1606,1617,1626],{"__ignoreMap":36},[40,1559,1560,1563,1565,1568],{"class":42,"line":43},[40,1561,1562],{"class":46},"@app.route",[40,1564,1033],{"class":427},[40,1566,1567],{"class":50},"\"\u002Flog-test\"",[40,1569,481],{"class":427},[40,1571,1572,1574,1577],{"class":42,"line":61},[40,1573,755],{"class":90},[40,1575,1576],{"class":46}," log_test",[40,1578,761],{"class":427},[40,1580,1581,1584,1587],{"class":42,"line":77},[40,1582,1583],{"class":427},"    app.logger.info(",[40,1585,1586],{"class":50},"\"Log test endpoint hit\"",[40,1588,481],{"class":427},[40,1590,1591,1593,1596,1599],{"class":42,"line":84},[40,1592,994],{"class":90},[40,1594,1595],{"class":50}," \"ok\"",[40,1597,1598],{"class":427},", ",[40,1600,1601],{"class":54},"200\n",[40,1603,1604],{"class":42,"line":109},[40,1605,81],{"emptyLinePlaceholder":80},[40,1607,1608,1610,1612,1615],{"class":42,"line":115},[40,1609,1562],{"class":46},[40,1611,1033],{"class":427},[40,1613,1614],{"class":50},"\"\u002Flog-error\"",[40,1616,481],{"class":427},[40,1618,1619,1621,1624],{"class":42,"line":121},[40,1620,755],{"class":90},[40,1622,1623],{"class":46}," log_error",[40,1625,761],{"class":427},[40,1627,1628,1630,1633,1635,1638],{"class":42,"line":127},[40,1629,1087],{"class":90},[40,1631,1632],{"class":54}," RuntimeError",[40,1634,1033],{"class":427},[40,1636,1637],{"class":50},"\"Intentional logging test error\"",[40,1639,481],{"class":427},[14,1641,1642],{},"Then test:",[31,1644,1646],{"className":33,"code":1645,"language":35,"meta":36,"style":36},"curl -i http:\u002F\u002F127.0.0.1\u002Flog-test\ncurl -i http:\u002F\u002F127.0.0.1\u002Flog-error\n",[26,1647,1648,1659],{"__ignoreMap":36},[40,1649,1650,1653,1656],{"class":42,"line":43},[40,1651,1652],{"class":46},"curl",[40,1654,1655],{"class":54}," -i",[40,1657,1658],{"class":50}," http:\u002F\u002F127.0.0.1\u002Flog-test\n",[40,1660,1661,1663,1665],{"class":42,"line":61},[40,1662,1652],{"class":46},[40,1664,1655],{"class":54},[40,1666,1667],{"class":50}," http:\u002F\u002F127.0.0.1\u002Flog-error\n",[327,1669,1670],{"start":144},[330,1671,1672],{},[333,1673,1674],{},"Inspect all three log layers",[14,1676,1677],{},"Gunicorn and service logs:",[31,1679,1681],{"className":33,"code":1680,"language":35,"meta":36,"style":36},"sudo journalctl -u myflaskapp -n 100 --no-pager\nsudo journalctl -u myflaskapp -f\n",[26,1682,1683,1699],{"__ignoreMap":36},[40,1684,1685,1687,1689,1691,1693,1695,1697],{"class":42,"line":43},[40,1686,47],{"class":46},[40,1688,267],{"class":50},[40,1690,270],{"class":54},[40,1692,273],{"class":50},[40,1694,276],{"class":54},[40,1696,279],{"class":54},[40,1698,282],{"class":54},[40,1700,1701,1703,1705,1707,1709],{"class":42,"line":61},[40,1702,47],{"class":46},[40,1704,267],{"class":50},[40,1706,270],{"class":54},[40,1708,273],{"class":50},[40,1710,1711],{"class":54}," -f\n",[14,1713,1714],{},"Nginx logs:",[31,1716,1718],{"className":33,"code":1717,"language":35,"meta":36,"style":36},"sudo tail -n 100 \u002Fvar\u002Flog\u002Fnginx\u002Faccess.log\nsudo tail -n 100 \u002Fvar\u002Flog\u002Fnginx\u002Ferror.log\nsudo tail -n 100 \u002Fvar\u002Flog\u002Fnginx\u002Fmyflaskapp_access.log\nsudo tail -n 100 \u002Fvar\u002Flog\u002Fnginx\u002Fmyflaskapp_error.log\n",[26,1719,1720,1732,1744,1757],{"__ignoreMap":36},[40,1721,1722,1724,1726,1728,1730],{"class":42,"line":43},[40,1723,47],{"class":46},[40,1725,290],{"class":50},[40,1727,276],{"class":54},[40,1729,279],{"class":54},[40,1731,297],{"class":50},[40,1733,1734,1736,1738,1740,1742],{"class":42,"line":61},[40,1735,47],{"class":46},[40,1737,290],{"class":50},[40,1739,276],{"class":54},[40,1741,279],{"class":54},[40,1743,311],{"class":50},[40,1745,1746,1748,1750,1752,1754],{"class":42,"line":77},[40,1747,47],{"class":46},[40,1749,290],{"class":50},[40,1751,276],{"class":54},[40,1753,279],{"class":54},[40,1755,1756],{"class":50}," \u002Fvar\u002Flog\u002Fnginx\u002Fmyflaskapp_access.log\n",[40,1758,1759,1761,1763,1765,1767],{"class":42,"line":84},[40,1760,47],{"class":46},[40,1762,290],{"class":50},[40,1764,276],{"class":54},[40,1766,279],{"class":54},[40,1768,1769],{"class":50}," \u002Fvar\u002Flog\u002Fnginx\u002Fmyflaskapp_error.log\n",[14,1771,1772],{},"Flask file logs:",[31,1774,1776],{"className":33,"code":1775,"language":35,"meta":36,"style":36},"sudo tail -n 100 \u002Fvar\u002Flog\u002Fmyflaskapp\u002Fapp.log\n",[26,1777,1778],{"__ignoreMap":36},[40,1779,1780,1782,1784,1786,1788],{"class":42,"line":43},[40,1781,47],{"class":46},[40,1783,290],{"class":50},[40,1785,276],{"class":54},[40,1787,279],{"class":54},[40,1789,1790],{"class":50}," \u002Fvar\u002Flog\u002Fmyflaskapp\u002Fapp.log\n",[327,1792,1793],{"start":150},[330,1794,1795],{},[333,1796,1797],{},"Add log rotation for custom file logs",[14,1799,1800],{},"If you keep Flask file logs, rotate them.",[31,1802,1806],{"className":1803,"code":1804,"language":1805,"meta":36,"style":36},"language-conf shiki shiki-themes github-light github-dark","\u002Fvar\u002Flog\u002Fmyflaskapp\u002F*.log {\n    daily\n    rotate 14\n    compress\n    missingok\n    notifempty\n    copytruncate\n}\n","conf",[26,1807,1808,1813,1818,1823,1828,1833,1838,1843],{"__ignoreMap":36},[40,1809,1810],{"class":42,"line":43},[40,1811,1812],{},"\u002Fvar\u002Flog\u002Fmyflaskapp\u002F*.log {\n",[40,1814,1815],{"class":42,"line":61},[40,1816,1817],{},"    daily\n",[40,1819,1820],{"class":42,"line":77},[40,1821,1822],{},"    rotate 14\n",[40,1824,1825],{"class":42,"line":84},[40,1826,1827],{},"    compress\n",[40,1829,1830],{"class":42,"line":109},[40,1831,1832],{},"    missingok\n",[40,1834,1835],{"class":42,"line":115},[40,1836,1837],{},"    notifempty\n",[40,1839,1840],{"class":42,"line":121},[40,1841,1842],{},"    copytruncate\n",[40,1844,1845],{"class":42,"line":127},[40,1846,1424],{},[14,1848,1849],{},"Save as:",[31,1851,1853],{"className":33,"code":1852,"language":35,"meta":36,"style":36},"sudo nano \u002Fetc\u002Flogrotate.d\u002Fmyflaskapp\n",[26,1854,1855],{"__ignoreMap":36},[40,1856,1857,1859,1862],{"class":42,"line":43},[40,1858,47],{"class":46},[40,1860,1861],{"class":50}," nano",[40,1863,1864],{"class":50}," \u002Fetc\u002Flogrotate.d\u002Fmyflaskapp\n",[14,1866,1867],{},"Test it:",[31,1869,1871],{"className":33,"code":1870,"language":35,"meta":36,"style":36},"sudo logrotate -d \u002Fetc\u002Flogrotate.d\u002Fmyflaskapp\n",[26,1872,1873],{"__ignoreMap":36},[40,1874,1875,1877,1880,1883],{"class":42,"line":43},[40,1876,47],{"class":46},[40,1878,1879],{"class":50}," logrotate",[40,1881,1882],{"class":54}," -d",[40,1884,1864],{"class":50},[327,1886,1887],{"start":156},[330,1888,1889],{},[333,1890,1891],{},"Standardize log content",[14,1893,1894],{},"Include:",[341,1896,1897,1900,1903,1906,1909],{},[330,1898,1899],{},"timestamp",[330,1901,1902],{},"level",[330,1904,1905],{},"module or logger name",[330,1907,1908],{},"request path where relevant",[330,1910,1911],{},"traceback for exceptions",[14,1913,1914],{},"Avoid:",[341,1916,1917,1920,1923,1926,1929],{},[330,1918,1919],{},"secrets",[330,1921,1922],{},"tokens",[330,1924,1925],{},"passwords",[330,1927,1928],{},"full session contents",[330,1930,1931],{},"environment variable dumps",[327,1933,1934],{"start":162},[330,1935,1936],{},[333,1937,1938],{},"Use this as the default production baseline",[14,1940,1941],{},"Recommended baseline:",[341,1943,1944,1947,1952,1958,1964],{},[330,1945,1946],{},"Flask app logs to stream and optional rotating file",[330,1948,1949,1950],{},"Gunicorn logs to ",[26,1951,28],{},[330,1953,1954,1955],{},"Nginx logs to ",[26,1956,1957],{},"\u002Fvar\u002Flog\u002Fnginx\u002F",[330,1959,1960,1963],{},[26,1961,1962],{},"logrotate"," for custom files",[330,1965,1966],{},"explicit testing after every deployment",[18,1968,1970],{"id":1969},"common-causes","Common Causes",[341,1972,1973,1986,1992,2002,2011,2024,2038,2047],{},[330,1974,1975,1985],{},[333,1976,1977,1978,1981,1982],{},"Gunicorn started without ",[26,1979,1980],{},"--access-logfile"," or ",[26,1983,1984],{},"--error-logfile"," → process logs are incomplete → enable both flags and restart the service.",[330,1987,1988,1991],{},[333,1989,1990],{},"Flask logger configured too late in startup"," → early exceptions never reach your handlers → initialize logging during app creation.",[330,1993,1994,1997,1998,2001],{},[333,1995,1996],{},"Duplicate handlers attached on reload or app factory reuse"," → repeated log lines → guard with ",[26,1999,2000],{},"if not app.logger.handlers"," and disable unwanted propagation.",[330,2003,2004,2010],{},[333,2005,2006,2007],{},"Service user cannot write to ",[26,2008,2009],{},"\u002Fvar\u002Flog\u002F\u003Capp>"," → app log file stays empty or throws permission errors → fix ownership and permissions for the Gunicorn\u002Fsystemd user.",[330,2012,2013,2016,2017,2020,2021,1101],{},[333,2014,2015],{},"Only Flask file logging is configured"," → Gunicorn startup and worker crashes are missed → inspect ",[26,2018,2019],{},"journalctl"," and enable ",[26,2022,2023],{},"--capture-output",[330,2025,2026,2029,2030,2033,2034,2037],{},[333,2027,2028],{},"Nginx logs are being written to a different file than expected"," → proxy errors appear missing → verify ",[26,2031,2032],{},"access_log"," and ",[26,2035,2036],{},"error_log"," in the active server block.",[330,2039,2040,2043,2044,2046],{},[333,2041,2042],{},"Log rotation is missing for custom files"," → logs grow until disk usage becomes a production issue → configure ",[26,2045,1962],{}," or use journald retention.",[330,2048,2049,2052,2053,2056],{},[333,2050,2051],{},"Exceptions are swallowed by custom handlers"," → 500s happen without tracebacks → use ",[26,2054,2055],{},"app.logger.exception(...)"," and re-raise or return a controlled logged response.",[18,2058,2060],{"id":2059},"debugging-section","Debugging Section",[14,2062,2063],{},"Check service state:",[31,2065,2067],{"className":33,"code":2066,"language":35,"meta":36,"style":36},"sudo systemctl status myflaskapp\nsudo systemctl cat myflaskapp\nps aux | grep gunicorn\n",[26,2068,2069,2079,2090],{"__ignoreMap":36},[40,2070,2071,2073,2075,2077],{"class":42,"line":43},[40,2072,47],{"class":46},[40,2074,243],{"class":50},[40,2076,1349],{"class":50},[40,2078,259],{"class":50},[40,2080,2081,2083,2085,2088],{"class":42,"line":61},[40,2082,47],{"class":46},[40,2084,243],{"class":50},[40,2086,2087],{"class":50}," cat",[40,2089,259],{"class":50},[40,2091,2092,2095,2098,2100,2103],{"class":42,"line":77},[40,2093,2094],{"class":46},"ps",[40,2096,2097],{"class":50}," aux",[40,2099,97],{"class":90},[40,2101,2102],{"class":46}," grep",[40,2104,2105],{"class":50}," gunicorn\n",[14,2107,2108],{},"Check Gunicorn and systemd logs:",[31,2110,2112],{"className":33,"code":2111,"language":35,"meta":36,"style":36},"sudo journalctl -u myflaskapp -n 200 --no-pager\nsudo journalctl -u myflaskapp -f\n",[26,2113,2114,2131],{"__ignoreMap":36},[40,2115,2116,2118,2120,2122,2124,2126,2129],{"class":42,"line":43},[40,2117,47],{"class":46},[40,2119,267],{"class":50},[40,2121,270],{"class":54},[40,2123,273],{"class":50},[40,2125,276],{"class":54},[40,2127,2128],{"class":54}," 200",[40,2130,282],{"class":54},[40,2132,2133,2135,2137,2139,2141],{"class":42,"line":61},[40,2134,47],{"class":46},[40,2136,267],{"class":50},[40,2138,270],{"class":54},[40,2140,273],{"class":50},[40,2142,1711],{"class":54},[14,2144,2145],{},"Check Nginx configuration and logs:",[31,2147,2149],{"className":33,"code":2148,"language":35,"meta":36,"style":36},"sudo nginx -t\nsudo tail -n 100 \u002Fvar\u002Flog\u002Fnginx\u002Faccess.log\nsudo tail -n 100 \u002Fvar\u002Flog\u002Fnginx\u002Ferror.log\nsudo tail -n 100 \u002Fvar\u002Flog\u002Fnginx\u002Fmyflaskapp_access.log\nsudo tail -n 100 \u002Fvar\u002Flog\u002Fnginx\u002Fmyflaskapp_error.log\n",[26,2150,2151,2159,2171,2183,2195],{"__ignoreMap":36},[40,2152,2153,2155,2157],{"class":42,"line":43},[40,2154,47],{"class":46},[40,2156,1439],{"class":50},[40,2158,1442],{"class":54},[40,2160,2161,2163,2165,2167,2169],{"class":42,"line":61},[40,2162,47],{"class":46},[40,2164,290],{"class":50},[40,2166,276],{"class":54},[40,2168,279],{"class":54},[40,2170,297],{"class":50},[40,2172,2173,2175,2177,2179,2181],{"class":42,"line":77},[40,2174,47],{"class":46},[40,2176,290],{"class":50},[40,2178,276],{"class":54},[40,2180,279],{"class":54},[40,2182,311],{"class":50},[40,2184,2185,2187,2189,2191,2193],{"class":42,"line":84},[40,2186,47],{"class":46},[40,2188,290],{"class":50},[40,2190,276],{"class":54},[40,2192,279],{"class":54},[40,2194,1756],{"class":50},[40,2196,2197,2199,2201,2203,2205],{"class":42,"line":109},[40,2198,47],{"class":46},[40,2200,290],{"class":50},[40,2202,276],{"class":54},[40,2204,279],{"class":54},[40,2206,1769],{"class":50},[14,2208,2209],{},"Check Flask file logs and permissions:",[31,2211,2213],{"className":33,"code":2212,"language":35,"meta":36,"style":36},"sudo tail -n 100 \u002Fvar\u002Flog\u002Fmyflaskapp\u002Fapp.log\nls -lah \u002Fvar\u002Flog\u002Fmyflaskapp\nls -lah \u002Frun\u002Fmyflaskapp.sock\n",[26,2214,2215,2227,2235],{"__ignoreMap":36},[40,2216,2217,2219,2221,2223,2225],{"class":42,"line":43},[40,2218,47],{"class":46},[40,2220,290],{"class":50},[40,2222,276],{"class":54},[40,2224,279],{"class":54},[40,2226,1790],{"class":50},[40,2228,2229,2231,2233],{"class":42,"line":61},[40,2230,1498],{"class":46},[40,2232,1501],{"class":54},[40,2234,58],{"class":50},[40,2236,2237,2239,2241],{"class":42,"line":77},[40,2238,1498],{"class":46},[40,2240,1501],{"class":54},[40,2242,2243],{"class":50}," \u002Frun\u002Fmyflaskapp.sock\n",[14,2245,2246],{},"What to look for:",[341,2248,2249,2252,2258,2268,2271,2274],{},[330,2250,2251],{},"import errors during startup",[330,2253,2254,2257],{},[26,2255,2256],{},"Permission denied"," on log directory or socket",[330,2259,2260,2261,1981,2264,2267],{},"missing ",[26,2262,2263],{},"stdout",[26,2265,2266],{},"stderr"," capture",[330,2269,2270],{},"Nginx upstream connection errors",[330,2272,2273],{},"500 tracebacks present in Flask or Gunicorn logs but not both",[330,2275,2276],{},"requests reaching Nginx but not reaching Gunicorn",[14,2278,2279,2280,2285,2286,1101],{},"If Gunicorn is failing before request handling, see ",[2281,2282,2284],"a",{"href":2283},"\u002Ffix-issues\u002Fflask-gunicorn-service-failed-to-start","Flask Gunicorn Service Failed to Start",". If requests return 500, see ",[2281,2287,2289],{"href":2288},"\u002Ffix-issues\u002Fflask-500-internal-server-error-in-production","Flask 500 Internal Server Error in Production",[18,2291,2293],{"id":2292},"checklist","Checklist",[341,2295,2298,2307,2318,2324,2330,2336,2342,2348,2354],{"className":2296},[2297],"contains-task-list",[330,2299,2302,2306],{"className":2300},[2301],"task-list-item",[2303,2304],"input",{"disabled":80,"type":2305},"checkbox"," Flask application logs are written to stdout, journald, or a dedicated file path",[330,2308,2310,2312,2313,2033,2315,2317],{"className":2309},[2301],[2303,2311],{"disabled":80,"type":2305}," Gunicorn runs with ",[26,2314,1980],{},[26,2316,1984],{}," configured",[330,2319,2321,2323],{"className":2320},[2301],[2303,2322],{"disabled":80,"type":2305}," systemd captures Gunicorn stdout\u002Fstderr without startup errors",[330,2325,2327,2329],{"className":2326},[2301],[2303,2328],{"disabled":80,"type":2305}," Nginx access and error logs are enabled and readable",[330,2331,2333,2335],{"className":2332},[2301],[2303,2334],{"disabled":80,"type":2305}," The service user can write to custom log directories if file logging is used",[330,2337,2339,2341],{"className":2338},[2301],[2303,2340],{"disabled":80,"type":2305}," Log rotation is configured for file-based logs",[330,2343,2345,2347],{"className":2344},[2301],[2303,2346],{"disabled":80,"type":2305}," Test requests generate visible info and error entries",[330,2349,2351,2353],{"className":2350},[2301],[2303,2352],{"disabled":80,"type":2305}," Tracebacks appear for unhandled exceptions",[330,2355,2357,2359],{"className":2356},[2301],[2303,2358],{"disabled":80,"type":2305}," No secrets or sensitive request data are written to logs",[14,2361,2362,2363,1101],{},"For a full deployment validation pass, use ",[2281,2364,2366],{"href":2365},"\u002Fchecklist\u002Fflask-production-checklist-everything-you-must-do","Flask Production Checklist (Everything You Must Do)",[18,2368,2370],{"id":2369},"related-guides","Related Guides",[341,2372,2373,2379,2383,2387],{},[330,2374,2375],{},[2281,2376,2378],{"href":2377},"\u002Fdeploy\u002Fdeploy-flask-with-nginx-plus-gunicorn-step-by-step-guide","Deploy Flask with Nginx + Gunicorn (Step-by-Step Guide)",[330,2380,2381],{},[2281,2382,2284],{"href":2283},[330,2384,2385],{},[2281,2386,2289],{"href":2288},[330,2388,2389],{},[2281,2390,2366],{"href":2365},[18,2392,2394],{"id":2393},"faq","FAQ",[14,2396,2397,2400,2402],{},[333,2398,2399],{},"Q: Should I log from Flask, Gunicorn, and Nginx together?",[337,2401],{},"\nA: Yes. Each layer exposes different failures, so production debugging is much faster when all three are available.",[14,2404,2405,2408,2410],{},[333,2406,2407],{},"Q: Is journald enough for a small Flask deployment?",[337,2409],{},"\nA: Usually yes. It is often the simplest default for Gunicorn on Ubuntu with systemd.",[14,2412,2413,2420,2422],{},[333,2414,2415,2416,2419],{},"Q: Why is ",[26,2417,2418],{},"app.logger.info"," not showing up?",[337,2421],{},"\nA: The logger level may be too high, handlers may not be attached, or Gunicorn may not be capturing stdout\u002Fstderr.",[14,2424,2425,2428,2430],{},[333,2426,2427],{},"Q: Should I enable Gunicorn access logs if Nginx already has them?",[337,2429],{},"\nA: Usually optional. Many deployments keep Nginx access logs and rely on Gunicorn mainly for worker and error logs.",[14,2432,2433,2436,2438,2439,2441],{},[333,2434,2435],{},"Q: How do I test logging safely?",[337,2437],{},"\nA: Trigger a known endpoint that writes an info log and a controlled exception, then confirm entries in ",[26,2440,2019],{}," and Nginx logs.",[18,2443,2445],{"id":2444},"final-takeaway","Final Takeaway",[14,2447,2448,2449,2451],{},"Production Flask logging works best when each layer has a clear responsibility: Flask logs application events and exceptions, Gunicorn logs worker and runtime output, and Nginx logs requests and proxy failures. Start with ",[26,2450,28],{}," plus Nginx logs, verify output end-to-end, then add structured file logging or centralized shipping after the baseline is stable.",[2453,2454,2455],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":36,"searchDepth":61,"depth":61,"links":2457},[2458,2459,2460,2461,2462,2463,2464,2465,2466],{"id":20,"depth":61,"text":21},{"id":317,"depth":61,"text":318},{"id":324,"depth":61,"text":325},{"id":1969,"depth":61,"text":1970},{"id":2059,"depth":61,"text":2060},{"id":2292,"depth":61,"text":2293},{"id":2369,"depth":61,"text":2370},{"id":2393,"depth":61,"text":2394},{"id":2444,"depth":61,"text":2445},"Complete guide on flask production logging setup for Flask production environments.","md",{"ogTitle":5,"ogDescription":2467,"twitterCard":2470,"robots":2471,"canonical":2472},"summary_large_image","index, follow","https:\u002F\u002Fflask-deployment.com\u002Foptimize\u002Fflask-production-logging-setup","\u002Foptimize\u002Fflask-production-logging-setup",{"title":5,"description":2467},"optimize\u002Fflask-production-logging-setup","GKee66X_Hy5dTeubCskKzwsYdEv1ZY6Xo0uWNtTvEGQ",1776805765797]