[{"data":1,"prerenderedAt":1758},["ShallowReactive",2],{"\u002Foptimize\u002Fflask-monitoring-and-error-tracking-setup":3},{"id":4,"title":5,"body":6,"description":1748,"extension":1749,"meta":1750,"navigation":114,"path":1754,"seo":1755,"stem":1756,"__hash__":1757},"content\u002Foptimize\u002Fflask-monitoring-and-error-tracking-setup.md","Flask Monitoring and Error Tracking Setup",{"type":7,"value":8,"toc":1737},"minimark",[9,13,17,22,30,58,245,267,336,339,343,354,358,1170,1174,1256,1260,1263,1276,1279,1304,1307,1335,1338,1364,1367,1379,1382,1394,1397,1419,1422,1480,1483,1534,1537,1574,1578,1640,1644,1671,1675,1683,1691,1699,1707,1718,1726,1730,1733],[10,11,5],"h1",{"id":12},"flask-monitoring-and-error-tracking-setup",[14,15,16],"p",{},"If you're trying to add monitoring and error tracking to a Flask production deployment, this guide shows you how to set it up step-by-step. The goal is to capture application errors, verify service health, and make production issues visible before they become outages.",[18,19,21],"h2",{"id":20},"quick-fix-quick-setup","Quick Fix \u002F Quick Setup",[14,23,24,25,29],{},"Install a basic error tracker, add a health endpoint, and make Gunicorn logs visible in ",[26,27,28],"code",{},"journalctl",".",[31,32,37],"pre",{"className":33,"code":34,"language":35,"meta":36,"style":36},"language-bash shiki shiki-themes github-light github-dark","pip install sentry-sdk gunicorn\n","bash","",[26,38,39],{"__ignoreMap":36},[40,41,44,48,52,55],"span",{"class":42,"line":43},"line",1,[40,45,47],{"class":46},"sScJk","pip",[40,49,51],{"class":50},"sZZnC"," install",[40,53,54],{"class":50}," sentry-sdk",[40,56,57],{"class":50}," gunicorn\n",[31,59,63],{"className":60,"code":61,"language":62,"meta":36,"style":36},"language-python shiki shiki-themes github-light github-dark","# app.py\nfrom flask import Flask\nimport sentry_sdk\nfrom sentry_sdk.integrations.flask import FlaskIntegration\n\nsentry_sdk.init(\n    dsn=\"https:\u002F\u002FYOUR_KEY@o0.ingest.sentry.io\u002F0\",\n    integrations=[FlaskIntegration()],\n    traces_sample_rate=0.0,\n)\n\napp = Flask(__name__)\n\n@app.get(\"\u002Fhealth\")\ndef health():\n    return {\"status\": \"ok\"}, 200\n","python",[26,64,65,71,88,96,109,116,122,138,149,163,169,174,190,195,209,221],{"__ignoreMap":36},[40,66,67],{"class":42,"line":43},[40,68,70],{"class":69},"sJ8bj","# app.py\n",[40,72,74,78,82,85],{"class":42,"line":73},2,[40,75,77],{"class":76},"szBVR","from",[40,79,81],{"class":80},"sVt8B"," flask ",[40,83,84],{"class":76},"import",[40,86,87],{"class":80}," Flask\n",[40,89,91,93],{"class":42,"line":90},3,[40,92,84],{"class":76},[40,94,95],{"class":80}," sentry_sdk\n",[40,97,99,101,104,106],{"class":42,"line":98},4,[40,100,77],{"class":76},[40,102,103],{"class":80}," sentry_sdk.integrations.flask ",[40,105,84],{"class":76},[40,107,108],{"class":80}," FlaskIntegration\n",[40,110,112],{"class":42,"line":111},5,[40,113,115],{"emptyLinePlaceholder":114},true,"\n",[40,117,119],{"class":42,"line":118},6,[40,120,121],{"class":80},"sentry_sdk.init(\n",[40,123,125,129,132,135],{"class":42,"line":124},7,[40,126,128],{"class":127},"s4XuR","    dsn",[40,130,131],{"class":76},"=",[40,133,134],{"class":50},"\"https:\u002F\u002FYOUR_KEY@o0.ingest.sentry.io\u002F0\"",[40,136,137],{"class":80},",\n",[40,139,141,144,146],{"class":42,"line":140},8,[40,142,143],{"class":127},"    integrations",[40,145,131],{"class":76},[40,147,148],{"class":80},"[FlaskIntegration()],\n",[40,150,152,155,157,161],{"class":42,"line":151},9,[40,153,154],{"class":127},"    traces_sample_rate",[40,156,131],{"class":76},[40,158,160],{"class":159},"sj4cs","0.0",[40,162,137],{"class":80},[40,164,166],{"class":42,"line":165},10,[40,167,168],{"class":80},")\n",[40,170,172],{"class":42,"line":171},11,[40,173,115],{"emptyLinePlaceholder":114},[40,175,177,180,182,185,188],{"class":42,"line":176},12,[40,178,179],{"class":80},"app ",[40,181,131],{"class":76},[40,183,184],{"class":80}," Flask(",[40,186,187],{"class":159},"__name__",[40,189,168],{"class":80},[40,191,193],{"class":42,"line":192},13,[40,194,115],{"emptyLinePlaceholder":114},[40,196,198,201,204,207],{"class":42,"line":197},14,[40,199,200],{"class":46},"@app.get",[40,202,203],{"class":80},"(",[40,205,206],{"class":50},"\"\u002Fhealth\"",[40,208,168],{"class":80},[40,210,212,215,218],{"class":42,"line":211},15,[40,213,214],{"class":76},"def",[40,216,217],{"class":46}," health",[40,219,220],{"class":80},"():\n",[40,222,224,227,230,233,236,239,242],{"class":42,"line":223},16,[40,225,226],{"class":76},"    return",[40,228,229],{"class":80}," {",[40,231,232],{"class":50},"\"status\"",[40,234,235],{"class":80},": ",[40,237,238],{"class":50},"\"ok\"",[40,240,241],{"class":80},"}, ",[40,243,244],{"class":159},"200\n",[31,246,250],{"className":247,"code":248,"language":249,"meta":36,"style":36},"language-ini shiki shiki-themes github-light github-dark","# \u002Fetc\u002Fsystemd\u002Fsystem\u002Fflask.service\n[Service]\nEnvironment=\"GUNICORN_CMD_ARGS=--access-logfile - --error-logfile - --capture-output --log-level info\"\n","ini",[26,251,252,257,262],{"__ignoreMap":36},[40,253,254],{"class":42,"line":43},[40,255,256],{},"# \u002Fetc\u002Fsystemd\u002Fsystem\u002Fflask.service\n",[40,258,259],{"class":42,"line":73},[40,260,261],{},"[Service]\n",[40,263,264],{"class":42,"line":90},[40,265,266],{},"Environment=\"GUNICORN_CMD_ARGS=--access-logfile - --error-logfile - --capture-output --log-level info\"\n",[31,268,270],{"className":33,"code":269,"language":35,"meta":36,"style":36},"sudo systemctl daemon-reload\nsudo systemctl restart flask\nsudo systemctl status flask\ncurl -I http:\u002F\u002F127.0.0.1:8000\u002Fhealth\njournalctl -u flask -n 100 --no-pager\n",[26,271,272,283,295,306,317],{"__ignoreMap":36},[40,273,274,277,280],{"class":42,"line":43},[40,275,276],{"class":46},"sudo",[40,278,279],{"class":50}," systemctl",[40,281,282],{"class":50}," daemon-reload\n",[40,284,285,287,289,292],{"class":42,"line":73},[40,286,276],{"class":46},[40,288,279],{"class":50},[40,290,291],{"class":50}," restart",[40,293,294],{"class":50}," flask\n",[40,296,297,299,301,304],{"class":42,"line":90},[40,298,276],{"class":46},[40,300,279],{"class":50},[40,302,303],{"class":50}," status",[40,305,294],{"class":50},[40,307,308,311,314],{"class":42,"line":98},[40,309,310],{"class":46},"curl",[40,312,313],{"class":159}," -I",[40,315,316],{"class":50}," http:\u002F\u002F127.0.0.1:8000\u002Fhealth\n",[40,318,319,321,324,327,330,333],{"class":42,"line":111},[40,320,28],{"class":46},[40,322,323],{"class":159}," -u",[40,325,326],{"class":50}," flask",[40,328,329],{"class":159}," -n",[40,331,332],{"class":159}," 100",[40,334,335],{"class":159}," --no-pager\n",[14,337,338],{},"This gives you a working baseline: Flask error tracking with Sentry, a health endpoint, and Gunicorn logs visible in the systemd journal. Expand it with uptime checks, Nginx access logs, and alerting.",[18,340,342],{"id":341},"whats-happening","What’s Happening",[14,344,345,346,349,350,353],{},"A Flask app can fail at multiple layers: application code, Gunicorn workers, systemd, Nginx, the database, or external APIs. Without health checks, logs, and exception reporting, production failures usually appear as generic ",[26,347,348],{},"500"," or ",[26,351,352],{},"502"," errors with little context. A minimal monitoring setup should provide three signals: health status, logs, and exception reporting.",[18,355,357],{"id":356},"step-by-step-guide","Step-by-Step Guide",[359,360,361,390,557,621,726,767,830,972,1009,1047,1115,1145],"ol",{},[362,363,364,368,371,372,375,376],"li",{},[365,366,367],"strong",{},"Install an error tracking SDK",[369,370],"br",{},"Install ",[26,373,374],{},"sentry-sdk"," in the same environment as your Flask app.",[31,377,379],{"className":33,"code":378,"language":35,"meta":36,"style":36},"pip install sentry-sdk\n",[26,380,381],{"__ignoreMap":36},[40,382,383,385,387],{"class":42,"line":43},[40,384,47],{"class":46},[40,386,51],{"class":50},[40,388,389],{"class":50}," sentry-sdk\n",[362,391,392,395,397,398,501,503,504],{},[365,393,394],{},"Initialize error tracking at application startup",[369,396],{},"Add the SDK before handling requests.",[31,399,401],{"className":60,"code":400,"language":62,"meta":36,"style":36},"# app.py\nfrom flask import Flask\nimport sentry_sdk\nfrom sentry_sdk.integrations.flask import FlaskIntegration\n\nsentry_sdk.init(\n    dsn=\"https:\u002F\u002FYOUR_KEY@o0.ingest.sentry.io\u002F0\",\n    integrations=[FlaskIntegration()],\n    traces_sample_rate=0.0,\n    send_default_pii=False,\n)\n\napp = Flask(__name__)\n",[26,402,403,407,417,423,433,437,441,451,459,469,481,485,489],{"__ignoreMap":36},[40,404,405],{"class":42,"line":43},[40,406,70],{"class":69},[40,408,409,411,413,415],{"class":42,"line":73},[40,410,77],{"class":76},[40,412,81],{"class":80},[40,414,84],{"class":76},[40,416,87],{"class":80},[40,418,419,421],{"class":42,"line":90},[40,420,84],{"class":76},[40,422,95],{"class":80},[40,424,425,427,429,431],{"class":42,"line":98},[40,426,77],{"class":76},[40,428,103],{"class":80},[40,430,84],{"class":76},[40,432,108],{"class":80},[40,434,435],{"class":42,"line":111},[40,436,115],{"emptyLinePlaceholder":114},[40,438,439],{"class":42,"line":118},[40,440,121],{"class":80},[40,442,443,445,447,449],{"class":42,"line":124},[40,444,128],{"class":127},[40,446,131],{"class":76},[40,448,134],{"class":50},[40,450,137],{"class":80},[40,452,453,455,457],{"class":42,"line":140},[40,454,143],{"class":127},[40,456,131],{"class":76},[40,458,148],{"class":80},[40,460,461,463,465,467],{"class":42,"line":151},[40,462,154],{"class":127},[40,464,131],{"class":76},[40,466,160],{"class":159},[40,468,137],{"class":80},[40,470,471,474,476,479],{"class":42,"line":165},[40,472,473],{"class":127},"    send_default_pii",[40,475,131],{"class":76},[40,477,478],{"class":159},"False",[40,480,137],{"class":80},[40,482,483],{"class":42,"line":171},[40,484,168],{"class":80},[40,486,487],{"class":42,"line":176},[40,488,115],{"emptyLinePlaceholder":114},[40,490,491,493,495,497,499],{"class":42,"line":192},[40,492,179],{"class":80},[40,494,131],{"class":76},[40,496,184],{"class":80},[40,498,187],{"class":159},[40,500,168],{"class":80},[369,502],{},"If you load the DSN from environment variables:",[31,505,507],{"className":60,"code":506,"language":62,"meta":36,"style":36},"import os\nsentry_sdk.init(\n    dsn=os.environ.get(\"SENTRY_DSN\"),\n    integrations=[FlaskIntegration()],\n    traces_sample_rate=0.0,\n)\n",[26,508,509,516,520,535,543,553],{"__ignoreMap":36},[40,510,511,513],{"class":42,"line":43},[40,512,84],{"class":76},[40,514,515],{"class":80}," os\n",[40,517,518],{"class":42,"line":73},[40,519,121],{"class":80},[40,521,522,524,526,529,532],{"class":42,"line":90},[40,523,128],{"class":127},[40,525,131],{"class":76},[40,527,528],{"class":80},"os.environ.get(",[40,530,531],{"class":50},"\"SENTRY_DSN\"",[40,533,534],{"class":80},"),\n",[40,536,537,539,541],{"class":42,"line":98},[40,538,143],{"class":127},[40,540,131],{"class":76},[40,542,148],{"class":80},[40,544,545,547,549,551],{"class":42,"line":111},[40,546,154],{"class":127},[40,548,131],{"class":76},[40,550,160],{"class":159},[40,552,137],{"class":80},[40,554,555],{"class":42,"line":118},[40,556,168],{"class":80},[362,558,559,562,564,565,604,606,607],{},[365,560,561],{},"Add a lightweight health endpoint",[369,563],{},"Keep this route fast and predictable.",[31,566,568],{"className":60,"code":567,"language":62,"meta":36,"style":36},"@app.get(\"\u002Fhealth\")\ndef health():\n    return {\"status\": \"ok\"}, 200\n",[26,569,570,580,588],{"__ignoreMap":36},[40,571,572,574,576,578],{"class":42,"line":43},[40,573,200],{"class":46},[40,575,203],{"class":80},[40,577,206],{"class":50},[40,579,168],{"class":80},[40,581,582,584,586],{"class":42,"line":73},[40,583,214],{"class":76},[40,585,217],{"class":46},[40,587,220],{"class":80},[40,589,590,592,594,596,598,600,602],{"class":42,"line":90},[40,591,226],{"class":76},[40,593,229],{"class":80},[40,595,232],{"class":50},[40,597,235],{"class":80},[40,599,238],{"class":50},[40,601,241],{"class":80},[40,603,244],{"class":159},[369,605],{},"Test it locally:",[31,608,610],{"className":33,"code":609,"language":35,"meta":36,"style":36},"curl -i http:\u002F\u002F127.0.0.1:8000\u002Fhealth\n",[26,611,612],{"__ignoreMap":36},[40,613,614,616,619],{"class":42,"line":43},[40,615,310],{"class":46},[40,617,618],{"class":159}," -i",[40,620,316],{"class":50},[362,622,623,626,628,629,632,633],{},[365,624,625],{},"Enable Gunicorn access and error logs",[369,627],{},"If Gunicorn runs under systemd, send logs to stdout\u002Fstderr so ",[26,630,631],{},"journald"," captures them.",[31,634,636],{"className":247,"code":635,"language":249,"meta":36,"style":36},"# \u002Fetc\u002Fsystemd\u002Fsystem\u002Fflask.service\n[Unit]\nDescription=Gunicorn instance for Flask app\nAfter=network.target\n\n[Service]\nUser=www-data\nGroup=www-data\nWorkingDirectory=\u002Fvar\u002Fwww\u002Fflask-app\nEnvironment=\"PATH=\u002Fvar\u002Fwww\u002Fflask-app\u002Fvenv\u002Fbin\"\nEnvironment=\"SENTRY_DSN=https:\u002F\u002FYOUR_KEY@o0.ingest.sentry.io\u002F0\"\nEnvironment=\"GUNICORN_CMD_ARGS=--access-logfile - --error-logfile - --capture-output --log-level info --timeout 30\"\nExecStart=\u002Fvar\u002Fwww\u002Fflask-app\u002Fvenv\u002Fbin\u002Fgunicorn -w 3 -b 127.0.0.1:8000 app:app\nRestart=always\nRestartSec=5\n\n[Install]\nWantedBy=multi-user.target\n",[26,637,638,642,647,652,657,661,665,670,675,680,685,690,695,700,705,710,714,720],{"__ignoreMap":36},[40,639,640],{"class":42,"line":43},[40,641,256],{},[40,643,644],{"class":42,"line":73},[40,645,646],{},"[Unit]\n",[40,648,649],{"class":42,"line":90},[40,650,651],{},"Description=Gunicorn instance for Flask app\n",[40,653,654],{"class":42,"line":98},[40,655,656],{},"After=network.target\n",[40,658,659],{"class":42,"line":111},[40,660,115],{"emptyLinePlaceholder":114},[40,662,663],{"class":42,"line":118},[40,664,261],{},[40,666,667],{"class":42,"line":124},[40,668,669],{},"User=www-data\n",[40,671,672],{"class":42,"line":140},[40,673,674],{},"Group=www-data\n",[40,676,677],{"class":42,"line":151},[40,678,679],{},"WorkingDirectory=\u002Fvar\u002Fwww\u002Fflask-app\n",[40,681,682],{"class":42,"line":165},[40,683,684],{},"Environment=\"PATH=\u002Fvar\u002Fwww\u002Fflask-app\u002Fvenv\u002Fbin\"\n",[40,686,687],{"class":42,"line":171},[40,688,689],{},"Environment=\"SENTRY_DSN=https:\u002F\u002FYOUR_KEY@o0.ingest.sentry.io\u002F0\"\n",[40,691,692],{"class":42,"line":176},[40,693,694],{},"Environment=\"GUNICORN_CMD_ARGS=--access-logfile - --error-logfile - --capture-output --log-level info --timeout 30\"\n",[40,696,697],{"class":42,"line":192},[40,698,699],{},"ExecStart=\u002Fvar\u002Fwww\u002Fflask-app\u002Fvenv\u002Fbin\u002Fgunicorn -w 3 -b 127.0.0.1:8000 app:app\n",[40,701,702],{"class":42,"line":197},[40,703,704],{},"Restart=always\n",[40,706,707],{"class":42,"line":211},[40,708,709],{},"RestartSec=5\n",[40,711,712],{"class":42,"line":223},[40,713,115],{"emptyLinePlaceholder":114},[40,715,717],{"class":42,"line":716},17,[40,718,719],{},"[Install]\n",[40,721,723],{"class":42,"line":722},18,[40,724,725],{},"WantedBy=multi-user.target\n",[362,727,728,731,733,734],{},[365,729,730],{},"Reload systemd and restart the Flask service",[369,732],{},"Apply the updated service definition.",[31,735,737],{"className":33,"code":736,"language":35,"meta":36,"style":36},"sudo systemctl daemon-reload\nsudo systemctl restart flask\nsudo systemctl status flask\n",[26,738,739,747,757],{"__ignoreMap":36},[40,740,741,743,745],{"class":42,"line":43},[40,742,276],{"class":46},[40,744,279],{"class":50},[40,746,282],{"class":50},[40,748,749,751,753,755],{"class":42,"line":73},[40,750,276],{"class":46},[40,752,279],{"class":50},[40,754,291],{"class":50},[40,756,294],{"class":50},[40,758,759,761,763,765],{"class":42,"line":90},[40,760,276],{"class":46},[40,762,279],{"class":50},[40,764,303],{"class":50},[40,766,294],{"class":50},[362,768,769,772,774,775,806,808,809],{},[365,770,771],{},"Verify Gunicorn logs in journald",[369,773],{},"Confirm startup output and request logs are visible.",[31,776,778],{"className":33,"code":777,"language":35,"meta":36,"style":36},"journalctl -u flask -n 200 --no-pager\njournalctl -u flask -f\n",[26,779,780,795],{"__ignoreMap":36},[40,781,782,784,786,788,790,793],{"class":42,"line":43},[40,783,28],{"class":46},[40,785,323],{"class":159},[40,787,326],{"class":50},[40,789,329],{"class":159},[40,791,792],{"class":159}," 200",[40,794,335],{"class":159},[40,796,797,799,801,803],{"class":42,"line":73},[40,798,28],{"class":46},[40,800,323],{"class":159},[40,802,326],{"class":50},[40,804,805],{"class":159}," -f\n",[369,807],{},"Look for:",[810,811,812,815,818,821,827],"ul",{},[362,813,814],{},"startup failures",[362,816,817],{},"import errors",[362,819,820],{},"worker boot failures",[362,822,823,824],{},"incoming ",[26,825,826],{},"GET \u002Fhealth",[362,828,829],{},"Python tracebacks",[362,831,832,835,837,838,942,944,945],{},[365,833,834],{},"Enable Nginx access and error logs",[369,836],{},"Make sure your site config logs requests and upstream errors.",[31,839,843],{"className":840,"code":841,"language":842,"meta":36,"style":36},"language-nginx shiki shiki-themes github-light github-dark","server {\n    listen 80;\n    server_name your-domain.com;\n\n    access_log \u002Fvar\u002Flog\u002Fnginx\u002Fflask_access.log;\n    error_log \u002Fvar\u002Flog\u002Fnginx\u002Fflask_error.log warn;\n\n    location \u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:8000;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n\n    location \u002Fhealth {\n        proxy_pass http:\u002F\u002F127.0.0.1:8000\u002Fhealth;\n        proxy_set_header Host $host;\n    }\n}\n","nginx",[26,844,845,850,855,860,864,869,874,878,883,888,893,898,903,908,913,917,922,927,931,936],{"__ignoreMap":36},[40,846,847],{"class":42,"line":43},[40,848,849],{},"server {\n",[40,851,852],{"class":42,"line":73},[40,853,854],{},"    listen 80;\n",[40,856,857],{"class":42,"line":90},[40,858,859],{},"    server_name your-domain.com;\n",[40,861,862],{"class":42,"line":98},[40,863,115],{"emptyLinePlaceholder":114},[40,865,866],{"class":42,"line":111},[40,867,868],{},"    access_log \u002Fvar\u002Flog\u002Fnginx\u002Fflask_access.log;\n",[40,870,871],{"class":42,"line":118},[40,872,873],{},"    error_log \u002Fvar\u002Flog\u002Fnginx\u002Fflask_error.log warn;\n",[40,875,876],{"class":42,"line":124},[40,877,115],{"emptyLinePlaceholder":114},[40,879,880],{"class":42,"line":140},[40,881,882],{},"    location \u002F {\n",[40,884,885],{"class":42,"line":151},[40,886,887],{},"        proxy_pass http:\u002F\u002F127.0.0.1:8000;\n",[40,889,890],{"class":42,"line":165},[40,891,892],{},"        proxy_set_header Host $host;\n",[40,894,895],{"class":42,"line":171},[40,896,897],{},"        proxy_set_header X-Real-IP $remote_addr;\n",[40,899,900],{"class":42,"line":176},[40,901,902],{},"        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n",[40,904,905],{"class":42,"line":192},[40,906,907],{},"        proxy_set_header X-Forwarded-Proto $scheme;\n",[40,909,910],{"class":42,"line":197},[40,911,912],{},"    }\n",[40,914,915],{"class":42,"line":211},[40,916,115],{"emptyLinePlaceholder":114},[40,918,919],{"class":42,"line":223},[40,920,921],{},"    location \u002Fhealth {\n",[40,923,924],{"class":42,"line":716},[40,925,926],{},"        proxy_pass http:\u002F\u002F127.0.0.1:8000\u002Fhealth;\n",[40,928,929],{"class":42,"line":722},[40,930,892],{},[40,932,934],{"class":42,"line":933},19,[40,935,912],{},[40,937,939],{"class":42,"line":938},20,[40,940,941],{},"}\n",[369,943],{},"Validate and reload Nginx:",[31,946,948],{"className":33,"code":947,"language":35,"meta":36,"style":36},"sudo nginx -t\nsudo systemctl reload nginx\n",[26,949,950,960],{"__ignoreMap":36},[40,951,952,954,957],{"class":42,"line":43},[40,953,276],{"class":46},[40,955,956],{"class":50}," nginx",[40,958,959],{"class":159}," -t\n",[40,961,962,964,966,969],{"class":42,"line":73},[40,963,276],{"class":46},[40,965,279],{"class":50},[40,967,968],{"class":50}," reload",[40,970,971],{"class":50}," nginx\n",[362,973,974,977,979,980,992,994,995],{},[365,975,976],{},"Test the health endpoint through both paths",[369,978],{},"Test Gunicorn directly:",[31,981,982],{"className":33,"code":609,"language":35,"meta":36,"style":36},[26,983,984],{"__ignoreMap":36},[40,985,986,988,990],{"class":42,"line":43},[40,987,310],{"class":46},[40,989,618],{"class":159},[40,991,316],{"class":50},[369,993],{},"Test through Nginx\u002Fpublic routing:",[31,996,998],{"className":33,"code":997,"language":35,"meta":36,"style":36},"curl -i https:\u002F\u002Fyour-domain\u002Fhealth\n",[26,999,1000],{"__ignoreMap":36},[40,1001,1002,1004,1006],{"class":42,"line":43},[40,1003,310],{"class":46},[40,1005,618],{"class":159},[40,1007,1008],{"class":50}," https:\u002F\u002Fyour-domain\u002Fhealth\n",[362,1010,1011,1014,1016,1017],{},[365,1012,1013],{},"Verify service environment variables",[369,1015],{},"Confirm the DSN and Gunicorn args are actually loaded.",[31,1018,1020],{"className":33,"code":1019,"language":35,"meta":36,"style":36},"sudo systemctl show flask --property=Environment\nsudo systemctl cat flask\n",[26,1021,1022,1036],{"__ignoreMap":36},[40,1023,1024,1026,1028,1031,1033],{"class":42,"line":43},[40,1025,276],{"class":46},[40,1027,279],{"class":50},[40,1029,1030],{"class":50}," show",[40,1032,326],{"class":50},[40,1034,1035],{"class":159}," --property=Environment\n",[40,1037,1038,1040,1042,1045],{"class":42,"line":73},[40,1039,276],{"class":46},[40,1041,279],{"class":50},[40,1043,1044],{"class":50}," cat",[40,1046,294],{"class":50},[362,1048,1049,1052,1054,1055,1095,1097,1098,1112,1114],{},[365,1050,1051],{},"Trigger a controlled test exception",[369,1053],{},"Use a non-public route or staging environment to confirm error delivery.",[31,1056,1058],{"className":60,"code":1057,"language":62,"meta":36,"style":36},"@app.get(\"\u002Fdebug-error\")\ndef debug_error():\n    raise RuntimeError(\"test sentry error\")\n",[26,1059,1060,1071,1080],{"__ignoreMap":36},[40,1061,1062,1064,1066,1069],{"class":42,"line":43},[40,1063,200],{"class":46},[40,1065,203],{"class":80},[40,1067,1068],{"class":50},"\"\u002Fdebug-error\"",[40,1070,168],{"class":80},[40,1072,1073,1075,1078],{"class":42,"line":73},[40,1074,214],{"class":76},[40,1076,1077],{"class":46}," debug_error",[40,1079,220],{"class":80},[40,1081,1082,1085,1088,1090,1093],{"class":42,"line":90},[40,1083,1084],{"class":76},"    raise",[40,1086,1087],{"class":159}," RuntimeError",[40,1089,203],{"class":80},[40,1091,1092],{"class":50},"\"test sentry error\"",[40,1094,168],{"class":80},[369,1096],{},"Trigger it:",[31,1099,1101],{"className":33,"code":1100,"language":35,"meta":36,"style":36},"curl -i http:\u002F\u002F127.0.0.1:8000\u002Fdebug-error\n",[26,1102,1103],{"__ignoreMap":36},[40,1104,1105,1107,1109],{"class":42,"line":43},[40,1106,310],{"class":46},[40,1108,618],{"class":159},[40,1110,1111],{"class":50}," http:\u002F\u002F127.0.0.1:8000\u002Fdebug-error\n",[369,1113],{},"Confirm the event appears in your error tracking dashboard. Remove or protect this route after testing.",[362,1116,1117,1120,1122,1123,1131,1133,1134],{},[365,1118,1119],{},"Add an uptime monitor",[369,1121],{},"Point your uptime provider or internal monitoring system at:",[31,1124,1129],{"className":1125,"code":1127,"language":1128,"meta":36},[1126],"language-text","https:\u002F\u002Fyour-domain\u002Fhealth\n","text",[26,1130,1127],{"__ignoreMap":36},[369,1132],{},"Alert on:",[810,1135,1136,1139,1142],{},[362,1137,1138],{},"endpoint unavailable",[362,1140,1141],{},"non-200 responses",[362,1143,1144],{},"repeated timeouts",[362,1146,1147,1150,1152,1153],{},[365,1148,1149],{},"Document where each signal lives",[369,1151],{},"Use one source for each type of issue:",[810,1154,1155,1158,1164,1167],{},[362,1156,1157],{},"app exceptions → error tracking dashboard",[362,1159,1160,1161],{},"process logs → ",[26,1162,1163],{},"journalctl -u flask",[362,1165,1166],{},"reverse proxy failures → Nginx logs",[362,1168,1169],{},"public availability → uptime monitor",[18,1171,1173],{"id":1172},"common-causes","Common Causes",[810,1175,1176,1185,1194,1207,1220,1234,1244,1250],{},[362,1177,1178,1181,1182,1184],{},[365,1179,1180],{},"No application error tracking initialized"," → Exceptions only appear as generic ",[26,1183,348],{}," responses → Install and initialize an error tracking SDK at app startup.",[362,1186,1187,1190,1191,1193],{},[365,1188,1189],{},"Gunicorn logs not enabled"," → Failures happen but nothing useful appears in ",[26,1192,28],{}," → Start Gunicorn with access logs, error logs, and output capture enabled.",[362,1195,1196,1203,1204,29],{},[365,1197,1198,1199,1202],{},"Missing ",[26,1200,1201],{},"\u002Fhealth"," endpoint"," → Uptime tools cannot distinguish app availability from page-level failures → Add a lightweight route that returns ",[26,1205,1206],{},"200",[362,1208,1209,1212,1213,349,1216,1219],{},[365,1210,1211],{},"systemd environment variables not loaded"," → DSN, API keys, or config values are missing in production → Use ",[26,1214,1215],{},"Environment=",[26,1217,1218],{},"EnvironmentFile="," and restart the service.",[362,1221,1222,1225,1226,1229,1230,1233],{},[365,1223,1224],{},"Nginx logs disabled or using wrong paths"," → Reverse proxy failures are hard to diagnose → Enable ",[26,1227,1228],{},"access_log"," and ",[26,1231,1232],{},"error_log"," in the site config.",[362,1235,1236,1239,1240,1243],{},[365,1237,1238],{},"Alerting not configured"," → Monitoring exists but nobody is notified → Add alerts for downtime, ",[26,1241,1242],{},"5xx"," spikes, and new unhandled exceptions.",[362,1245,1246,1249],{},[365,1247,1248],{},"Health checks pointed at a heavy route"," → Monitoring causes load or false failures → Point checks at a lightweight endpoint with predictable output.",[362,1251,1252,1255],{},[365,1253,1254],{},"Testing only local logs"," → Public routing or TLS issues are missed → Validate both the local Gunicorn listener and the public domain.",[18,1257,1259],{"id":1258},"debugging-section","Debugging Section",[14,1261,1262],{},"Check package installation:",[31,1264,1266],{"className":33,"code":1265,"language":35,"meta":36,"style":36},"pip show sentry-sdk\n",[26,1267,1268],{"__ignoreMap":36},[40,1269,1270,1272,1274],{"class":42,"line":43},[40,1271,47],{"class":46},[40,1273,1030],{"class":50},[40,1275,389],{"class":50},[14,1277,1278],{},"Check Flask and Gunicorn service status:",[31,1280,1282],{"className":33,"code":1281,"language":35,"meta":36,"style":36},"sudo systemctl status flask\nsudo systemctl restart flask\n",[26,1283,1284,1294],{"__ignoreMap":36},[40,1285,1286,1288,1290,1292],{"class":42,"line":43},[40,1287,276],{"class":46},[40,1289,279],{"class":50},[40,1291,303],{"class":50},[40,1293,294],{"class":50},[40,1295,1296,1298,1300,1302],{"class":42,"line":73},[40,1297,276],{"class":46},[40,1299,279],{"class":50},[40,1301,291],{"class":50},[40,1303,294],{"class":50},[14,1305,1306],{},"Check recent application and Gunicorn logs:",[31,1308,1309],{"className":33,"code":777,"language":35,"meta":36,"style":36},[26,1310,1311,1325],{"__ignoreMap":36},[40,1312,1313,1315,1317,1319,1321,1323],{"class":42,"line":43},[40,1314,28],{"class":46},[40,1316,323],{"class":159},[40,1318,326],{"class":50},[40,1320,329],{"class":159},[40,1322,792],{"class":159},[40,1324,335],{"class":159},[40,1326,1327,1329,1331,1333],{"class":42,"line":73},[40,1328,28],{"class":46},[40,1330,323],{"class":159},[40,1332,326],{"class":50},[40,1334,805],{"class":159},[14,1336,1337],{},"Check service environment and full unit definition:",[31,1339,1340],{"className":33,"code":1019,"language":35,"meta":36,"style":36},[26,1341,1342,1354],{"__ignoreMap":36},[40,1343,1344,1346,1348,1350,1352],{"class":42,"line":43},[40,1345,276],{"class":46},[40,1347,279],{"class":50},[40,1349,1030],{"class":50},[40,1351,326],{"class":50},[40,1353,1035],{"class":159},[40,1355,1356,1358,1360,1362],{"class":42,"line":73},[40,1357,276],{"class":46},[40,1359,279],{"class":50},[40,1361,1044],{"class":50},[40,1363,294],{"class":50},[14,1365,1366],{},"Check local health endpoint:",[31,1368,1369],{"className":33,"code":609,"language":35,"meta":36,"style":36},[26,1370,1371],{"__ignoreMap":36},[40,1372,1373,1375,1377],{"class":42,"line":43},[40,1374,310],{"class":46},[40,1376,618],{"class":159},[40,1378,316],{"class":50},[14,1380,1381],{},"Check public health endpoint:",[31,1383,1384],{"className":33,"code":997,"language":35,"meta":36,"style":36},[26,1385,1386],{"__ignoreMap":36},[40,1387,1388,1390,1392],{"class":42,"line":43},[40,1389,310],{"class":46},[40,1391,618],{"class":159},[40,1393,1008],{"class":50},[14,1395,1396],{},"Check Nginx configuration and reload status:",[31,1398,1399],{"className":33,"code":947,"language":35,"meta":36,"style":36},[26,1400,1401,1409],{"__ignoreMap":36},[40,1402,1403,1405,1407],{"class":42,"line":43},[40,1404,276],{"class":46},[40,1406,956],{"class":50},[40,1408,959],{"class":159},[40,1410,1411,1413,1415,1417],{"class":42,"line":73},[40,1412,276],{"class":46},[40,1414,279],{"class":50},[40,1416,968],{"class":50},[40,1418,971],{"class":50},[14,1420,1421],{},"Check Nginx logs:",[31,1423,1425],{"className":33,"code":1424,"language":35,"meta":36,"style":36},"sudo tail -n 100 \u002Fvar\u002Flog\u002Fnginx\u002Ferror.log\nsudo tail -n 100 \u002Fvar\u002Flog\u002Fnginx\u002Faccess.log\nsudo tail -n 100 \u002Fvar\u002Flog\u002Fnginx\u002Fflask_error.log\nsudo tail -n 100 \u002Fvar\u002Flog\u002Fnginx\u002Fflask_access.log\n",[26,1426,1427,1441,1454,1467],{"__ignoreMap":36},[40,1428,1429,1431,1434,1436,1438],{"class":42,"line":43},[40,1430,276],{"class":46},[40,1432,1433],{"class":50}," tail",[40,1435,329],{"class":159},[40,1437,332],{"class":159},[40,1439,1440],{"class":50}," \u002Fvar\u002Flog\u002Fnginx\u002Ferror.log\n",[40,1442,1443,1445,1447,1449,1451],{"class":42,"line":73},[40,1444,276],{"class":46},[40,1446,1433],{"class":50},[40,1448,329],{"class":159},[40,1450,332],{"class":159},[40,1452,1453],{"class":50}," \u002Fvar\u002Flog\u002Fnginx\u002Faccess.log\n",[40,1455,1456,1458,1460,1462,1464],{"class":42,"line":90},[40,1457,276],{"class":46},[40,1459,1433],{"class":50},[40,1461,329],{"class":159},[40,1463,332],{"class":159},[40,1465,1466],{"class":50}," \u002Fvar\u002Flog\u002Fnginx\u002Fflask_error.log\n",[40,1468,1469,1471,1473,1475,1477],{"class":42,"line":98},[40,1470,276],{"class":46},[40,1472,1433],{"class":50},[40,1474,329],{"class":159},[40,1476,332],{"class":159},[40,1478,1479],{"class":50}," \u002Fvar\u002Flog\u002Fnginx\u002Fflask_access.log\n",[14,1481,1482],{},"Check Gunicorn listener or socket:",[31,1484,1486],{"className":33,"code":1485,"language":35,"meta":36,"style":36},"ss -ltnp | grep gunicorn || ss -lx | grep gunicorn\nps aux | grep gunicorn\n",[26,1487,1488,1520],{"__ignoreMap":36},[40,1489,1490,1493,1496,1499,1502,1505,1508,1511,1514,1516,1518],{"class":42,"line":43},[40,1491,1492],{"class":46},"ss",[40,1494,1495],{"class":159}," -ltnp",[40,1497,1498],{"class":76}," |",[40,1500,1501],{"class":46}," grep",[40,1503,1504],{"class":50}," gunicorn",[40,1506,1507],{"class":76}," ||",[40,1509,1510],{"class":46}," ss",[40,1512,1513],{"class":159}," -lx",[40,1515,1498],{"class":76},[40,1517,1501],{"class":46},[40,1519,57],{"class":50},[40,1521,1522,1525,1528,1530,1532],{"class":42,"line":73},[40,1523,1524],{"class":46},"ps",[40,1526,1527],{"class":50}," aux",[40,1529,1498],{"class":76},[40,1531,1501],{"class":46},[40,1533,57],{"class":50},[14,1535,1536],{},"What to look for:",[810,1538,1539,1545,1548,1551,1557,1568,1571],{},[362,1540,1541,1542],{},"missing ",[26,1543,1544],{},"SENTRY_DSN",[362,1546,1547],{},"worker boot errors",[362,1549,1550],{},"import\u002Fmodule errors",[362,1552,1553,1556],{},[26,1554,1555],{},"502 Bad Gateway"," upstream failures in Nginx",[362,1558,1559,349,1562,1565,1566],{},[26,1560,1561],{},"403",[26,1563,1564],{},"404"," on ",[26,1567,1201],{},[362,1569,1570],{},"app listening on the wrong port or socket",[362,1572,1573],{},"test exception not reaching the error tracker",[18,1575,1577],{"id":1576},"checklist","Checklist",[810,1579,1582,1596,1604,1610,1616,1622,1628,1634],{"className":1580},[1581],"contains-task-list",[362,1583,1586,1590,1591,1593,1594],{"className":1584},[1585],"task-list-item",[1587,1588],"input",{"disabled":114,"type":1589},"checkbox"," Flask has a working ",[26,1592,1201],{}," endpoint returning ",[26,1595,1206],{},[362,1597,1599,1601,1602],{"className":1598},[1585],[1587,1600],{"disabled":114,"type":1589}," Gunicorn access and error logs are enabled and visible in ",[26,1603,28],{},[362,1605,1607,1609],{"className":1606},[1585],[1587,1608],{"disabled":114,"type":1589}," systemd restart policy is enabled for the Flask service",[362,1611,1613,1615],{"className":1612},[1585],[1587,1614],{"disabled":114,"type":1589}," Nginx access and error logs are enabled for the site",[362,1617,1619,1621],{"className":1618},[1585],[1587,1620],{"disabled":114,"type":1589}," Error tracking SDK is initialized with the correct production DSN",[362,1623,1625,1627],{"className":1624},[1585],[1587,1626],{"disabled":114,"type":1589}," A test exception reaches the error tracking dashboard",[362,1629,1631,1633],{"className":1630},[1585],[1587,1632],{"disabled":114,"type":1589}," An uptime monitor checks the public health endpoint",[362,1635,1637,1639],{"className":1636},[1585],[1587,1638],{"disabled":114,"type":1589}," Alerts are configured for downtime and repeated application errors",[18,1641,1643],{"id":1642},"related-guides","Related Guides",[810,1645,1646,1653,1659,1665],{},[362,1647,1648],{},[1649,1650,1652],"a",{"href":1651},"\u002Fdeploy\u002Fdeploy-flask-with-nginx-plus-gunicorn-step-by-step-guide","Deploy Flask with Nginx + Gunicorn (Step-by-Step Guide)",[362,1654,1655],{},[1649,1656,1658],{"href":1657},"\u002Foptimize\u002Fflask-production-logging-setup","Flask Production Logging Setup",[362,1660,1661],{},[1649,1662,1664],{"href":1663},"\u002Ffix-issues\u002Ffix-flask-502-bad-gateway-step-by-step-guide","Fix Flask 502 Bad Gateway (Step-by-Step Guide)",[362,1666,1667],{},[1649,1668,1670],{"href":1669},"\u002Fchecklist\u002Fflask-production-checklist-everything-you-must-do","Flask Production Checklist (Everything You Must Do)",[18,1672,1674],{"id":1673},"faq","FAQ",[14,1676,1677,1680,1682],{},[365,1678,1679],{},"Q: Do I need both logging and error tracking?",[369,1681],{},"\nA: Yes. Error tracking captures exceptions well, while logs help diagnose startup failures, routing issues, upstream errors, and non-exception events.",[14,1684,1685,1688,1690],{},[365,1686,1687],{},"Q: What is the minimum production monitoring setup for Flask?",[369,1689],{},"\nA: A health endpoint, Gunicorn and Nginx logs, systemd service visibility, one uptime check, and one exception tracking tool.",[14,1692,1693,1696,1698],{},[365,1694,1695],{},"Q: Should health checks go through Nginx or directly to Gunicorn?",[369,1697],{},"\nA: Use both during setup. Direct checks validate the app process; public checks validate the full production path.",[14,1700,1701,1704,1706],{},[365,1702,1703],{},"Q: Why am I not seeing Flask exceptions in the dashboard?",[369,1705],{},"\nA: The SDK may not be initialized, the DSN may be missing, outbound network access may be blocked, or the exception is being handled before reporting.",[14,1708,1709,1715,1717],{},[365,1710,1711,1712,1714],{},"Q: Should ",[26,1713,1201],{}," check the database?",[369,1716],{},"\nA: Use a shallow health check for load balancers and uptime probes. Add a separate deep check if you need dependency validation.",[14,1719,1720,1723,1725],{},[365,1721,1722],{},"Q: Why log Gunicorn to stdout\u002Fstderr?",[369,1724],{},"\nA: It keeps logs visible in the systemd journal and simplifies log collection on VPS and container-based deployments.",[18,1727,1729],{"id":1728},"final-takeaway","Final Takeaway",[14,1731,1732],{},"A usable monitoring setup for Flask is not one tool. Combine a health endpoint, visible Gunicorn and Nginx logs, systemd service visibility, and exception tracking so you can detect, locate, and fix failures quickly.",[1734,1735,1736],"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 .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 .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}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}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":36,"searchDepth":73,"depth":73,"links":1738},[1739,1740,1741,1742,1743,1744,1745,1746,1747],{"id":20,"depth":73,"text":21},{"id":341,"depth":73,"text":342},{"id":356,"depth":73,"text":357},{"id":1172,"depth":73,"text":1173},{"id":1258,"depth":73,"text":1259},{"id":1576,"depth":73,"text":1577},{"id":1642,"depth":73,"text":1643},{"id":1673,"depth":73,"text":1674},{"id":1728,"depth":73,"text":1729},"Complete guide on flask monitoring and error tracking setup for Flask production environments.","md",{"ogTitle":5,"ogDescription":1748,"twitterCard":1751,"robots":1752,"canonical":1753},"summary_large_image","index, follow","https:\u002F\u002Fflask-deployment.com\u002Foptimize\u002Fflask-monitoring-and-error-tracking-setup","\u002Foptimize\u002Fflask-monitoring-and-error-tracking-setup",{"title":5,"description":1748},"optimize\u002Fflask-monitoring-and-error-tracking-setup","IoVuS2DXul2Jr_1w9azZhAa3Q-LT1jLgauuDMKSw47Q",1776805765060]