{"id":359,"date":"2026-07-16T16:40:06","date_gmt":"2026-07-16T08:40:06","guid":{"rendered":"https:\/\/numsimlab.com\/?p=359"},"modified":"2026-07-16T16:40:06","modified_gmt":"2026-07-16T08:40:06","slug":"python-%e6%97%a5%e5%bf%97%e7%ae%a1%e7%90%86%e5%ae%8c%e6%95%b4%e6%8c%87%e5%8d%97","status":"publish","type":"post","link":"https:\/\/numsimlab.com\/?p=359","title":{"rendered":"Python \u65e5\u5fd7\u7ba1\u7406\u5b8c\u6574\u6307\u5357"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Python \u65e5\u5fd7\u7ba1\u7406\u5b8c\u6574\u6307\u5357 \u00b7 Python Logging Full Guide<\/title>\n<style>\n*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}\nhtml{scroll-behavior:smooth}\n:root{\n  --bg:#f8f9fa;--bg2:#fff;--ink:#1a1a2e;--muted:#6c7086;--rule:#e2e4eb;\n  --accent:#2563eb;--accent2:#16a34a;--accent3:#dc2626;--accent4:#d97706;--accent5:#7c3aed;\n  --card-bg:#fff;--code-bg:#f1f3f5;\n  --tag-g:#dcfce7;--tag-g-t:#166534;--tag-b:#dbeafe;--tag-b-t:#1e40af;\n  --tag-r:#fee2e2;--tag-r-t:#991b1b;--tag-y:#fef9c3;--tag-y-t:#713f12;--tag-p:#f3e8ff;--tag-p-t:#581c87;\n  --shadow:0 1px 3px rgba(0,0,.08);--radius:8px;--max-w:940px\n}\n[data-theme=\"dark\"]{\n  --bg:#0b0b1a;--bg2:#16162a;--ink:#e2e4f0;--muted:#7f8396;--rule:#26263e;\n  --accent:#60a5fa;--accent2:#4ade80;--accent3:#f87171;--accent4:#fbbf24;--accent5:#a78bfa;\n  --card-bg:#16162a;--code-bg:#1e1e36;\n  --tag-g:#14532d;--tag-g-t:#bbf7d0;--tag-b:#1e3a5f;--tag-b-t:#bfdbfe;\n  --tag-r:#7f1d1d;--tag-r-t:#fecaca;--tag-y:#713f12;--tag-y-t:#fef08a;\n  --tag-p:#3b1f6e;--tag-p-t:#e9d5ff;\n  --shadow:0 1px 3px rgba(0,0,.3)\n}\nbody{font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",\"Noto Sans SC\",\"PingFang SC\",\"Microsoft YaHei\",sans-serif;background:var(--bg);color:var(--ink);line-height:1.7;font-size:15px;transition:background .3s,color .3s}\nheader{position:fixed;top:0;left:0;right:0;z-index:100;background:var(--bg2);border-bottom:1px solid var(--rule);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);transition:background .3s}\n.header-inner{max-width:var(--max-w);margin:0 auto;display:flex;align-items:center;justify-content:space-between;padding:0 1.5rem;height:56px}\n.logo{font-weight:700;font-size:.95rem;color:var(--accent);display:flex;align-items:center;gap:.4rem}\n.controls{display:flex;align-items:center;gap:.5rem}\n.lang-switch{display:flex;border:1px solid var(--rule);border-radius:6px;overflow:hidden}\n.lang-switch button{background:0 0;border:none;color:var(--muted);padding:.3rem .7rem;font-size:.8rem;cursor:pointer;transition:all .2s;font-family:inherit}\n.lang-switch button.active{background:var(--accent);color:#fff}\n.lang-switch button:not(.active):hover{color:var(--ink);background:var(--rule)}\n.theme-toggle{background:0 0;border:1px solid var(--rule);border-radius:6px;color:var(--muted);width:34px;height:34px;font-size:1rem;cursor:pointer;display:flex;align-items:center;transition:all .2s}\n.theme-toggle:hover{color:var(--ink);background:var(--rule)}\nmain{max-width:var(--max-w);margin:0 auto;padding:80px 1.5rem 3rem}\n.lang-section{display:none}.lang-section.active{display:block}\nh1{font-size:1.9rem;font-weight:800;line-height:1.3;margin-bottom:.5rem;letter-spacing:-.02em}\nh1 .sub{display:block;font-size:.85rem;font-weight:400;color:var(--muted);margin-top:.25rem;letter-spacing:0}\nh2{font-size:1.35rem;font-weight:700;margin:2.5rem 0 1rem;padding-bottom:.5rem;border-bottom:2px solid var(--accent);letter-spacing:-.01em}\nh3{font-size:1.05rem;font-weight:600;margin:1.5rem 0 .6rem;color:var(--accent)}\nh4{font-size:.95rem;font-weight:600;margin:1rem 0 .4rem;color:var(--ink)}\np{margin-bottom:.8rem}\na{color:var(--accent);text-decoration:none}a:hover{text-decoration:underline}\n.hero{text-align:center;padding:2rem 0 1rem}\n.hero p{font-size:1rem;color:var(--muted);max-width:700px;margin:0 auto}\n.tag{display:inline-block;padding:.12rem .5rem;border-radius:4px;font-size:.72rem;font-weight:600;margin-right:.25rem;white-space:nowrap}\n.tag-g{background:var(--tag-g);color:var(--tag-g-t)}.tag-b{background:var(--tag-b);color:var(--tag-b-t)}\n.tag-r{background:var(--tag-r);color:var(--tag-r-t)}.tag-y{background:var(--tag-y);color:var(--tag-y-t)}.tag-p{background:var(--tag-p);color:var(--tag-p-t)}\n.card{background:var(--card-bg);border:1px solid var(--rule);border-radius:var(--radius);padding:1.25rem;margin-bottom:1rem;box-shadow:var(--shadow)}\n.info-box{background:var(--bg);border-left:4px solid var(--accent);padding:.9rem 1.1rem;margin:1rem 0;border-radius:0 var(--radius) var(--radius) 0;font-size:.88rem}\n.info-box strong{color:var(--accent)}\n.info-box.warn{border-left-color:var(--accent4)}.info-box.warn strong{color:var(--accent4)}\n.info-box.danger{border-left-color:var(--accent3)}.info-box.danger strong{color:var(--accent3)}\n.toc{background:var(--card-bg);border:1px solid var(--rule);border-radius:var(--radius);padding:1.15rem 1.4rem;margin-bottom:2rem;box-shadow:var(--shadow)}\n.toc h3{margin:0 0 .5rem;font-size:.9rem;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}\n.toc ol{padding-left:1.1rem;columns:2;column-gap:2rem}\n.toc li{margin-bottom:.25rem;font-size:.88rem}.toc a{color:var(--ink)}.toc a:hover{color:var(--accent);text-decoration:none}\npre.code-block{background:var(--code-bg);padding:.85rem 1rem;border-radius:var(--radius);overflow-x:auto;font-family:\"SF Mono\",Consolas,\"Courier New\",monospace;font-size:.82rem;line-height:1.5;margin:.6rem 0;border:1px solid var(--rule)}\ncode,.inline-code{background:var(--code-bg);padding:.12rem .4rem;border-radius:4px;font-family:\"SF Mono\",Consolas,\"Courier New\",monospace;font-size:.83rem;border:1px solid var(--rule)}\n.table-wrap{overflow-x:auto;margin:1.2rem 0}\ntable{width:100%;border-collapse:collapse;font-size:.82rem}\nthead th{background:var(--accent);color:#fff;padding:.6rem .5rem;text-align:center;font-weight:600;white-space:nowrap}\nthead th:first-child{border-radius:6px 0 0 0}thead th:last-child{border-radius:0 6px 0 0}\ntbody td{padding:.55rem .5rem;border-bottom:1px solid var(--rule);text-align:center;vertical-align:middle}\ntbody tr:nth-child(even){background:var(--bg)}\ntbody td:first-child{text-align:left;font-weight:600}\n.terminal{background:#1a1a2e;color:#a8e6cf;border-radius:var(--radius);padding:.9rem 1rem;font-family:\"SF Mono\",Consolas,\"Courier New\",monospace;font-size:.82rem;line-height:1.6;margin:.6rem 0;overflow-x:auto;border:1px solid #333}\n.terminal .prompt{color:#60a5fa}.terminal .comment{color:#6c7086;font-style:italic}.terminal .output{color:#e2e4f0}\n[data-theme=\"dark\"] .terminal{background:#08081a}\n.steps{counter-reset:step;list-style:none;padding:0}\n.steps li{counter-increment:step;position:relative;padding:.85rem 1rem .85rem 2.8rem;margin-bottom:.5rem;border-left:2px solid var(--rule);border-radius:0 var(--radius) 0;background:var(--card-bg);box-shadow:var(--shadow)}\n.steps li::before{content:counter(step);position:absolute;left:-13px;top:.85rem;width:26px;height:26px;border-radius:50%;background:var(--accent);color:#fff;display:flex;align-items:center;justify-content:center;font-size:.78rem;font-weight:700}\n.steps li .cmd{display:block;background:var(--code-bg);padding:.4rem .7rem;border-radius:5px;font-family:\"SF Mono\",Consolas,\"Courier New\",monospace;font-size:.82rem;margin:.3rem 0;overflow-x:auto;border:1px solid var(--rule)}\n.steps li .note{display:block;color:var(--muted);font-size:.82rem;margin-top:.2rem}\n.flow-diagram{background:var(--card-bg);border:1px solid var(--rule);border-radius:var(--radius);padding:1.25rem;margin:1.25rem 0;text-align:center}\n.flow-row{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:.35rem;margin:.4rem 0}\n.flow-item{display:inline-block;padding:.4rem .8rem;border-radius:6px;font-weight:600;font-size:.82rem;text-align:center;background:var(--accent);color:#fff;min-width:60px}\n.flow-item.green{background:var(--accent2)}.flow-item.red{background:var(--accent3)}.flow-item.yellow{background:var(--accent4);color:#1a1a2e}.flow-item.purple{background:var(--accent5)}\n.flow-arrow{color:var(--muted);font-size:1rem}\n.cmd-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:.75rem;margin:1rem 0}\n.cmd-card{background:var(--card-bg);border:1px solid var(--rule);border-radius:var(--radius);padding:.9rem;box-shadow:var(--shadow)}\n.cmd-card h4{margin:0 0 .35rem;font-size:.88rem;color:var(--accent)}\n.cmd-card .cmd{font-family:\"SF Mono\",Consolas,\"Courier New\",monospace;font-size:.8rem;background:var(--code-bg);padding:.3rem .5rem;border-radius:4px;display:block;margin-bottom:.3rem;border:1px solid var(--rule)}\n.cmd-card .desc{font-size:.8rem;color:var(--muted)}\n.two-col{display:grid;grid-template-columns:1fr 1fr;gap:1.25rem;margin:1.25rem 0}\n.col{background:var(--card-bg);border:1px solid var(--rule);border-radius:var(--radius);padding:1.25rem;box-shadow:var(--shadow)}\n.col h4{margin-top:0}\n.compare-box{display:grid;grid-template-columns:1fr 1fr;gap:1rem;margin:1rem 0}\n.compare-col{background:var(--card-bg);border:1px solid var(--rule);border-radius:var(--radius);padding:1rem;box-shadow:var(--shadow)}\n.compare-col h4{margin:0 0 .4rem;font-size:.88rem}\n.compare-col.bad h4{color:var(--accent3)}\n.compare-col.good h4{color:var(--accent2)}\npre.example{background:var(--code-bg);padding:.6rem .8rem;border-radius:6px;font-family:\"SF Mono\",Consolas,\"Courier New\",monospace;font-size:.78rem;line-height:1.5;margin:.4rem 0;border:1px solid var(--rule);color:var(--ink)}\nfooter{max-width:var(--max-w);margin:3rem auto 0;padding:2rem 1.5rem 3rem;border-top:1px solid var(--rule);text-align:center;font-size:.82rem;color:var(--muted)}\nfooter .links{display:flex;justify-content:center;gap:1.5rem;flex-wrap:wrap;margin-bottom:.8rem}\nfooter .links a{color:var(--muted)}footer .links a:hover{color:var(--accent)}\n@media(max-width:640px){\n  h1{font-size:1.4rem}.toc ol{columns:1}.header-inner{padding:0 1rem}main{padding:72px 1rem 2rem}\n  .steps li{padding-left:2.4rem}.steps li::before{left:-11px;width:22px;height:22px;font-size:.7rem}\n  .two-col{grid-template-columns:1fr}.cmd-grid{grid-template-columns:1fr}.compare-box{grid-template-columns:1fr}\n}\n<\/style>\n<\/head>\n<body>\n<header>\n  <div class=\"header-inner\">\n    <div class=\"logo\"><span>\ud83d\udcdd<\/span> Python \u65e5\u5fd7\u7ba1\u7406\u5b8c\u6574\u6307\u5357<\/div>\n    <div class=\"controls\">\n      <div class=\"lang-switch\">\n        <button class=\"active\" onclick=\"setLang('zh')\" id=\"btn-zh\">\u4e2d\u6587<\/button>\n        <button onclick=\"setLang('en')\" id=\"btn-en\">English<\/button>\n      <\/div>\n      <button class=\"theme-toggle\" onclick=\"toggleTheme()\" title=\"\u5207\u6362\u660e\u6697\u4e3b\u9898\">&#9788;<\/button>\n    <\/div>\n  <\/div>\n<\/header>\n<main>\n<!-- ======== \u4e2d\u6587\u7248 ======== -->\n<div class=\"lang-section active\" id=\"lang-zh\">\n<div class=\"hero\">\n  <h1>Python \u65e5\u5fd7\u7ba1\u7406\u5b8c\u6574\u6307\u5357\uff08\u5c42\u7ea7\u2192\u914d\u7f6e\u2192\u5b9e\u8df5\u5168\u94fe\u8def\uff09<span class=\"sub\">\u4ece logging \u57fa\u7840\u5230\u751f\u4ea7\u7ea7\u65e5\u5fd7\u7ba1\u7406\uff0c\u5f7b\u5e95\u7406\u89e3\u65e5\u5fd7\u7ea7\u522b\u4e0e\u6700\u4f73\u5b9e\u8df5<\/span><\/h1>\n  <p>\u65e5\u5fd7\u5c42\u7ea7\u6df1\u5ea6\u89e3\u6790\u3001logging \u6a21\u5757\u914d\u7f6e\u3001Handler \u4e0e Formatter\u3001\u6587\u4ef6\u7ba1\u7406\u7b56\u7565\u3001\u7ed3\u6784\u5316\u65e5\u5fd7\u3001\u6027\u80fd\u4f18\u5316\u3001\u4e0d\u540c\u73af\u5883\u914d\u7f6e\u5168\u8986\u76d6<\/p>\n<\/div>\n\n<div class=\"toc\">\n  <h3>\u76ee\u5f55<\/h3>\n  <ol>\n    <li><a href=\"#zh-1\">\u4e00\u3001\u4e3a\u4ec0\u4e48\u9700\u8981\u65e5\u5fd7\u7ba1\u7406<\/a><\/li>\n    <li><a href=\"#zh-2\">\u4e8c\u3001\u65e5\u5fd7\u5c42\u7ea7\uff08Level\uff09\u6df1\u5ea6\u89e3\u6790<\/a><\/li>\n    <li><a href=\"#zh-3\">\u4e09\u3001Python logging \u6a21\u5757\u67b6\u6784<\/a><\/li>\n    <li><a href=\"#zh-4\">\u56db\u3001\u914d\u7f6e\u65e5\u5fd7\u7cfb\u7edf\uff08\u4ee3\u7801\/\u5b57\u5178\/\u6587\u4ef6\uff09<\/a><\/li>\n    <li><a href=\"#zh-5\">\u4e94\u3001\u65e5\u5fd7\u6587\u4ef6\u7ba1\u7406\u7b56\u7565<\/a><\/li>\n    <li><a href=\"#zh-6\">\u516d\u3001\u4e0d\u540c\u73af\u5883\u7684\u65e5\u5fd7\u914d\u7f6e<\/a><\/li>\n    <li><a href=\"#zh-7\">\u4e03\u3001\u7ed3\u6784\u5316\u65e5\u5fd7\u4e0e JSON \u8f93\u51fa<\/a><\/li>\n    <li><a href=\"#zh-8\">\u516b\u3001\u6027\u80fd\u4f18\u5316\u4e0e\u5f02\u6b65\u65e5\u5fd7<\/a><\/li>\n    <li><a href=\"#zh-9\">\u4e5d\u3001\u65e5\u5fd7\u5b89\u5168\u4e0e\u654f\u611f\u4fe1\u606f\u5904\u7406<\/a><\/li>\n    <li><a href=\"#zh-10\">\u5341\u3001\u5e38\u89c1\u95ee\u9898\u4e0e\u6392\u67e5\u6a21\u677f<\/a><\/li>\n  <\/ol>\n<\/div>\n\n<!-- \u4e00\u3001\u4e3a\u4ec0\u4e48\u9700\u8981\u65e5\u5fd7 -->\n<h2 id=\"zh-1\">\u4e00\u3001\u4e3a\u4ec0\u4e48\u9700\u8981\u65e5\u5fd7\u7ba1\u7406<\/h2>\n<p>\u65e5\u5fd7\u662f\u7a0b\u5e8f\u8fd0\u884c\u65f6\u7684&#8221;\u9ed1\u5323\u5b50&#8221;\uff0c\u8bb0\u5f55\u7cfb\u7edf\u72b6\u6001\u3001\u7528\u6237\u884c\u4e3a\u3001\u5f02\u5e38\u4fe1\u606f\u548c\u6027\u80fd\u6570\u636e\u3002\u6ca1\u6709\u65e5\u5fd7\uff0c\u751f\u4ea7\u73af\u5883\u51fa\u95ee\u9898\u65f6\u5982\u540c\u76f2\u4eba\u6478\u8c61\u3002<\/p>\n\n<div class=\"compare-box\">\n  <div class=\"compare-col bad\">\n    <h4>\u274c \u65e0\u65e5\u5fd7\uff08\u95ee\u9898\u6392\u67e5\u56f0\u96be\uff09<\/h4>\n<pre class=\"example\"># \u7a0b\u5e8f\u5d29\u6e83\uff0c\u53ea\u80fd\u770b\u62a5\u9519\u5806\u6808\n# \u4e0d\u77e5\u9053\u8bf7\u6c42\u53c2\u6570\u662f\u4ec0\u4e48\n# \u4e0d\u77e5\u9053\u6570\u636e\u6d41\u8f6c\u5230\u54ea\u4e00\u6b65\n# \u4e0d\u77e5\u9053\u6027\u80fd\u74f6\u9888\u5728\u54ea\n# \u590d\u73b0 Bug \u9760\u731c\u6d4b<\/pre>\n    <p>\u7ebf\u4e0a\u95ee\u9898\u65e0\u6cd5\u5b9a\u4f4d\uff0c\u53ea\u80fd\u52a0 print \u91cd\u65b0\u90e8\u7f72\u6392\u67e5\uff0c\u6548\u7387\u6781\u4f4e\u3002<\/p>\n  <\/div>\n  <div class=\"compare-col good\">\n    <h4>\u2705 \u89c4\u8303\u65e5\u5fd7\uff08\u95ee\u9898\u4e00\u76ee\u4e86\u7136\uff09<\/h4>\n<pre class=\"example\">2026-07-16 14:32:10 [INFO] \u6536\u5230\u8bf7\u6c42: \/api\/calculate, params={\"a\":10,\"b\":0}\n2026-07-16 14:32:10 [DEBUG] \u6267\u884c\u8ba1\u7b97\u903b\u8f91: divide(10, 0)\n2026-07-16 14:32:10 [ERROR] \u8ba1\u7b97\u5f02\u5e38: ZeroDivisionError: division by zero\n2026-07-16 14:32:10 [INFO] \u8fd4\u56de\u54cd\u5e94: 400, {\"error\":\"\u9664\u6570\u4e0d\u80fd\u4e3a\u96f6\"}<\/pre>\n    <p>\u8bf7\u6c42\u53c2\u6570\u3001\u6267\u884c\u6d41\u7a0b\u3001\u5f02\u5e38\u4fe1\u606f\u3001\u54cd\u5e94\u7ed3\u679c\u5b8c\u6574\u53ef\u8ffd\u6eaf\u3002<\/p>\n  <\/div>\n<\/div>\n\n<div class=\"card\">\n  <h4>\u65e5\u5fd7\u4e94\u5927\u6838\u5fc3\u4ef7\u503c<\/h4>\n  <p><span class=\"tag tag-r\">\u6545\u969c\u6392\u67e5<\/span> \u751f\u4ea7\u73af\u5883\u51fa\u95ee\u9898\uff0c\u901a\u8fc7\u65e5\u5fd7\u5b9a\u4f4d\u6839\u56e0<\/p>\n  <p><span class=\"tag tag-b\">\u884c\u4e3a\u5ba1\u8ba1<\/span> \u8bb0\u5f55\u7528\u6237\u64cd\u4f5c\u3001\u6570\u636e\u53d8\u66f4\u3001\u5b89\u5168\u4e8b\u4ef6<\/p>\n  <p><span class=\"tag tag-g\">\u6027\u80fd\u5206\u6790<\/span> \u8bb0\u5f55\u8017\u65f6\uff0c\u53d1\u73b0\u6027\u80fd\u74f6\u9888<\/p>\n  <p><span class=\"tag tag-y\">\u4e1a\u52a1\u76d1\u63a7<\/span> \u7edf\u8ba1\u63a5\u53e3\u8c03\u7528\u91cf\u3001\u9519\u8bef\u7387\u3001\u541e\u5410\u91cf<\/p>\n  <p><span class=\"tag tag-p\">\u8c03\u8bd5\u8f85\u52a9<\/span> \u5f00\u53d1\u9636\u6bb5\u8ffd\u8e2a\u7a0b\u5e8f\u6267\u884c\u6d41\u7a0b<\/p>\n<\/div>\n\n<!-- \u4e8c\u3001\u65e5\u5fd7\u5c42\u7ea7 -->\n<h2 id=\"zh-2\">\u4e8c\u3001\u65e5\u5fd7\u5c42\u7ea7\uff08Level\uff09\u6df1\u5ea6\u89e3\u6790<\/h2>\n\n<div class=\"info-box\">\n  <strong>\u65e5\u5fd7\u5c42\u7ea7\u662f\u65e5\u5fd7\u7cfb\u7edf\u7684\u6838\u5fc3\u673a\u5236\uff0c\u901a\u8fc7\u4e0d\u540c\u7ea7\u522b\u533a\u5206\u4fe1\u606f\u7684\u91cd\u8981\u7a0b\u5ea6\uff0c\u5b9e\u73b0&#8221;\u4e0d\u540c\u573a\u666f\u770b\u4e0d\u540c\u65e5\u5fd7&#8221;\u7684\u7075\u6d3b\u63a7\u5236\u3002<\/strong>\n<\/div>\n\n<h3>2.1 Python \u6807\u51c6\u65e5\u5fd7\u7ea7\u522b<\/h3>\n<div class=\"table-wrap\">\n<table>\n  <thead>\n    <tr><th>\u7ea7\u522b<\/th><th>\u6570\u503c<\/th><th>\u542b\u4e49<\/th><th>\u4f7f\u7528\u573a\u666f<\/th><th>\u751f\u4ea7\u73af\u5883<\/th><\/tr>\n  <\/thead>\n  <tbody>\n    <tr><td><span class=\"tag tag-p\">DEBUG<\/span><\/td><td>10<\/td><td>\u8c03\u8bd5\u4fe1\u606f<\/td><td>\u53d8\u91cf\u503c\u3001\u51fd\u6570\u5165\u53c2\u3001\u6267\u884c\u6d41\u7a0b<\/td><td>\u5173\u95ed<\/td><\/tr>\n    <tr><td><span class=\"tag tag-b\">INFO<\/span><\/td><td>20<\/td><td>\u5e38\u89c4\u4fe1\u606f<\/td><td>\u670d\u52a1\u542f\u52a8\u3001\u8bf7\u6c42\u5904\u7406\u3001\u72b6\u6001\u53d8\u66f4<\/td><td>\u5f00\u542f<\/td><\/tr>\n    <tr><td><span class=\"tag tag-y\">WARNING<\/span><\/td><td>30<\/td><td>\u8b66\u544a\u4fe1\u606f<\/td><td>\u8d44\u6e90\u4e0d\u8db3\u3001\u914d\u7f6e\u964d\u7ea7\u3001\u975e\u81f4\u547d\u5f02\u5e38<\/td><td>\u5f00\u542f<\/td><\/tr>\n    <tr><td><span class=\"tag tag-r\">ERROR<\/span><\/td><td>40<\/td><td>\u9519\u8bef\u4fe1\u606f<\/td><td>\u529f\u80fd\u5f02\u5e38\u3001\u4e1a\u52a1\u5931\u8d25\u3001\u9700\u4eba\u5de5\u4ecb\u5165<\/td><td>\u5f00\u542f<\/td><\/tr>\n    <tr><td><span class=\"tag tag-r\" style=\"background:#991b1b;color:#fff\">CRITICAL<\/span><\/td><td>50<\/td><td>\u4e25\u91cd\u9519\u8bef<\/td><td>\u7cfb\u7edf\u5d29\u6e83\u3001\u6570\u636e\u4e22\u5931\u3001\u5b89\u5168\u4e8b\u4ef6<\/td><td>\u5f00\u542f<\/td><\/tr>\n  <\/tbody>\n<\/table>\n<\/div>\n\n<h3>2.2 \u5982\u4f55\u6b63\u786e\u9009\u62e9\u65e5\u5fd7\u7ea7\u522b<\/h3>\n<pre class=\"code-block\">import logging\n\nlogger = logging.getLogger(__name__)\n\n# DEBUG\uff1a\u5f00\u53d1\u8c03\u8bd5\uff0c\u751f\u4ea7\u4e0d\u8f93\u51fa\nlogger.debug(f\"\u51fd\u6570 divide \u88ab\u8c03\u7528\uff0c\u53c2\u6570: a={a}, b={b}\")\nlogger.debug(f\"\u6570\u636e\u5e93\u67e5\u8be2 SQL: {sql}\")\n\n# INFO\uff1a\u5173\u952e\u4e1a\u52a1\u8282\u70b9\uff0c\u751f\u4ea7\u9700\u8981\nlogger.info(f\"\u7528\u6237 {user_id} \u767b\u5f55\u6210\u529f\uff0cIP: {client_ip}\")\nlogger.info(f\"\u8ba2\u5355 {order_id} \u521b\u5efa\u6210\u529f\uff0c\u91d1\u989d: {amount}\")\nlogger.info(\"\u670d\u52a1\u542f\u52a8\u5b8c\u6210\uff0c\u76d1\u542c\u7aef\u53e3 8000\")\n\n# WARNING\uff1a\u4e0d\u5f71\u54cd\u4e3b\u6d41\u7a0b\u4f46\u9700\u8981\u5173\u6ce8\nlogger.warning(f\"\u6570\u636e\u5e93\u8fde\u63a5\u6c60\u4f7f\u7528\u7387\u8d85\u8fc7 80%: {usage}%\")\nlogger.warning(f\"\u8bf7\u6c42\u91cd\u8bd5\u7b2c {retry_count} \u6b21\uff0cURL: {url}\")\nlogger.warning(\"\u4f7f\u7528\u9ed8\u8ba4\u914d\u7f6e\uff0c\u672a\u627e\u5230 .env \u6587\u4ef6\")\n\n# ERROR\uff1a\u529f\u80fd\u5f02\u5e38\uff0c\u9700\u8981\u6392\u67e5\u4fee\u590d\nlogger.error(f\"\u652f\u4ed8\u63a5\u53e3\u8c03\u7528\u5931\u8d25: {e}\", exc_info=True)\nlogger.error(f\"\u8ba2\u5355 {order_id} \u72b6\u6001\u66f4\u65b0\u5931\u8d25\uff0c\u5f53\u524d\u72b6\u6001: {status}\")\n\n# CRITICAL\uff1a\u7cfb\u7edf\u7ea7\u707e\u96be\nlogger.critical(\"\u6570\u636e\u5e93\u8fde\u63a5\u5168\u90e8\u65ad\u5f00\uff0c\u670d\u52a1\u4e0d\u53ef\u7528\")\nlogger.critical(\"\u78c1\u76d8\u7a7a\u95f4\u4e0d\u8db3\uff0c\u5199\u5165\u64cd\u4f5c\u5df2\u4e2d\u6b62\")\n<\/pre>\n\n<h3>2.3 \u65e5\u5fd7\u7ea7\u522b\u8fc7\u6ee4\u539f\u7406<\/h3>\n<p>Logger \u548c Handler \u5404\u81ea\u6709\u7ea7\u522b\u8bbe\u7f6e\uff0c\u6d88\u606f\u53ea\u6709\u540c\u65f6\u6ee1\u8db3\u4e24\u8005\u7ea7\u522b\u624d\u4f1a\u8f93\u51fa\u3002<\/p>\n\n<div class=\"flow-diagram\">\n  <div class=\"flow-row\">\n    <span class=\"flow-item green\">\u4ea7\u751f\u65e5\u5fd7<\/span>\n    <span class=\"flow-arrow\">&rarr;<\/span>\n    <span class=\"flow-item\">Logger \u7ea7\u522b\u8fc7\u6ee4<\/span>\n    <span class=\"flow-arrow\">&rarr;<\/span>\n    <span class=\"flow-item yellow\">Handler \u7ea7\u522b\u8fc7\u6ee4<\/span>\n    <span class=\"flow-arrow\">&rarr;<\/span>\n    <span class=\"flow-item purple\">Formatter \u683c\u5f0f\u5316<\/span>\n    <span class=\"flow-arrow\">&rarr;<\/span>\n    <span class=\"flow-item green\">\u8f93\u51fa<\/span>\n  <\/div>\n<\/div>\n\n<pre class=\"code-block\"># \u793a\u4f8b\uff1aLogger \u7ea7\u522b\u4e3a INFO\uff0cHandler \u7ea7\u522b\u4e3a ERROR\n# INFO \u7ea7\u522b\u7684\u65e5\u5fd7\u4f1a\u88ab Logger \u63a5\u6536\uff0c\u4f46\u88ab Handler \u8fc7\u6ee4\n# ERROR \u7ea7\u522b\u7684\u65e5\u5fd7\u4f1a\u901a\u8fc7\u6240\u6709\u8fc7\u6ee4\n\nlogger = logging.getLogger(\"myapp\")\nlogger.setLevel(logging.INFO)           # \u63a5\u6536 INFO \u53ca\u4ee5\u4e0a\n\nhandler = logging.StreamHandler()\nhandler.setLevel(logging.ERROR)         # \u53ea\u8f93\u51fa ERROR \u53ca\u4ee5\u4e0a\nlogger.addHandler(handler)\n\nlogger.info(\"\u8fd9\u6761\u4e0d\u4f1a\u8f93\u51fa\")    # \u88ab Handler \u8fc7\u6ee4\nlogger.error(\"\u8fd9\u6761\u4f1a\u8f93\u51fa\")     # \u901a\u8fc7\u6240\u6709\u8fc7\u6ee4\n<\/pre>\n\n<!-- \u4e09\u3001logging \u67b6\u6784 -->\n<h2 id=\"zh-3\">\u4e09\u3001Python logging \u6a21\u5757\u67b6\u6784<\/h2>\n\n<h3>3.1 \u6838\u5fc3\u7ec4\u4ef6\u5173\u7cfb<\/h3>\n<pre class=\"code-block\">Logger\uff08\u8bb0\u5f55\u5668\uff09\n  \u251c\u2500\u2500 \u5c42\u7ea7\u547d\u540d\uff1a\"myapp.api.auth\" \u7ee7\u627f \"myapp.api\"\n  \u251c\u2500\u2500 \u7ea7\u522b\u8fc7\u6ee4\uff1asetLevel()\n  \u251c\u2500\u2500 \u4f20\u64ad\u5f00\u5173\uff1apropagate = True\/False\n  \u2514\u2500\u2500 Handler\uff08\u5904\u7406\u5668\uff09\n        \u251c\u2500\u2500 StreamHandler    \u2192 \u8f93\u51fa\u5230\u63a7\u5236\u53f0\n        \u251c\u2500\u2500 FileHandler      \u2192 \u8f93\u51fa\u5230\u6587\u4ef6\n        \u251c\u2500\u2500 RotatingFileHandler \u2192 \u6309\u5927\u5c0f\u8f6e\u8f6c\n        \u251c\u2500\u2500 TimedRotatingFileHandler \u2192 \u6309\u65f6\u95f4\u8f6e\u8f6c\n        \u2514\u2500\u2500 \u7ea7\u522b\u8fc7\u6ee4 + Formatter\uff08\u683c\u5f0f\u5668\uff09\n              \u2514\u2500\u2500 \"%(asctime)s [%(levelname)s] %(message)s\"\n<\/pre>\n\n<h3>3.2 Logger \u5c42\u7ea7\u4e0e\u7ee7\u627f<\/h3>\n<p>Logger \u91c7\u7528\u70b9\u53f7\u5206\u9694\u7684\u547d\u540d\u7a7a\u95f4\uff0c\u5f62\u6210\u6811\u5f62\u7ed3\u6784\uff0c\u5b50 Logger \u7ee7\u627f\u7236 Logger \u7684\u914d\u7f6e\u3002<\/p>\n\n<pre class=\"code-block\">import logging\n\n# \u6839 Logger\nroot = logging.getLogger()           # \"\"\n\n# \u5b50 Logger\napp = logging.getLogger(\"myapp\")     # \u7ee7\u627f root\napi = logging.getLogger(\"myapp.api\") # \u7ee7\u627f myapp\nauth = logging.getLogger(\"myapp.api.auth\") # \u7ee7\u627f myapp.api\n\n# \u914d\u7f6e root\uff0c\u6240\u6709\u5b50 Logger \u9ed8\u8ba4\u7ee7\u627f\nroot.setLevel(logging.WARNING)\nhandler = logging.StreamHandler()\nroot.addHandler(handler)\n\n# myapp.api.auth \u4f1a\u7ee7\u627f root \u7684 Handler \u548c Level\n# \u9664\u975e\u81ea\u5df1 addHandler \u6216 setLevel\n<\/pre>\n\n<div class=\"info-box warn\">\n  <strong>\u6ce8\u610f\uff1a\u5982\u679c\u4e0d\u914d\u7f6e\u6839 Logger\uff0c\u76f4\u63a5\u4f7f\u7528 logging.info()\uff0cPython \u4f1a\u521b\u5efa\u4e00\u4e2a\u9ed8\u8ba4 Handler\uff08\u8f93\u51fa\u5230 stderr\uff0c\u7ea7\u522b WARNING\uff09\u3002\u751f\u4ea7\u73af\u5883\u5fc5\u987b\u663e\u5f0f\u914d\u7f6e\u3002<\/strong>\n<\/div>\n\n<!-- \u56db\u3001\u914d\u7f6e\u65e5\u5fd7\u7cfb\u7edf -->\n<h2 id=\"zh-4\">\u56db\u3001\u914d\u7f6e\u65e5\u5fd7\u7cfb\u7edf\uff08\u4ee3\u7801\/\u5b57\u5178\/\u6587\u4ef6\uff09<\/h2>\n\n<h3>4.1 \u4ee3\u7801\u65b9\u5f0f\u914d\u7f6e\uff08\u6700\u57fa\u7840\uff09<\/h3>\n<pre class=\"code-block\">import logging\nimport sys\n\ndef setup_logging(level: int = logging.INFO) -> None:\n    \"\"\"\u57fa\u7840\u65e5\u5fd7\u914d\u7f6e\u3002\"\"\"\n    formatter = logging.Formatter(\n        fmt=\"%(asctime)s [%(levelname)-8s] %(name)s:%(lineno)d - %(message)s\",\n        datefmt=\"%Y-%m-%d %H:%M:%S\"\n    )\n\n    # \u63a7\u5236\u53f0 Handler\n    console = logging.StreamHandler(sys.stdout)\n    console.setLevel(level)\n    console.setFormatter(formatter)\n\n    # \u6587\u4ef6 Handler\n    file_handler = logging.FileHandler(\"app.log\", encoding=\"utf-8\")\n    file_handler.setLevel(logging.DEBUG)\n    file_handler.setFormatter(formatter)\n\n    # \u6839 Logger\n    root = logging.getLogger()\n    root.setLevel(logging.DEBUG)\n    root.addHandler(console)\n    root.addHandler(file_handler)\n\n\n# \u4f7f\u7528\nsetup_logging()\nlogger = logging.getLogger(__name__)\nlogger.info(\"\u5e94\u7528\u542f\u52a8\")\n<\/pre>\n\n<h3>4.2 dictConfig \u65b9\u5f0f\uff08\u63a8\u8350\uff09<\/h3>\n<pre class=\"code-block\">import logging.config\n\nLOGGING_CONFIG = {\n    \"version\": 1,\n    \"disable_existing_loggers\": False,\n\n    \"formatters\": {\n        \"standard\": {\n            \"format\": \"%(asctime)s [%(levelname)-8s] %(name)s:%(lineno)d - %(message)s\",\n            \"datefmt\": \"%Y-%m-%d %H:%M:%S\"\n        },\n        \"detailed\": {\n            \"format\": \"%(asctime)s [%(levelname)-8s] %(name)s %(filename)s:%(lineno)d %(funcName)s() - %(message)s\"\n        }\n    },\n\n    \"handlers\": {\n        \"console\": {\n            \"class\": \"logging.StreamHandler\",\n            \"level\": \"INFO\",\n            \"formatter\": \"standard\",\n            \"stream\": \"ext:\/\/sys.stdout\"\n        },\n        \"file\": {\n            \"class\": \"logging.handlers.RotatingFileHandler\",\n            \"level\": \"DEBUG\",\n            \"formatter\": \"detailed\",\n            \"filename\": \"logs\/app.log\",\n            \"maxBytes\": 10485760,    # 10MB\n            \"backupCount\": 5,\n            \"encoding\": \"utf-8\"\n        },\n        \"error_file\": {\n            \"class\": \"logging.handlers.RotatingFileHandler\",\n            \"level\": \"ERROR\",\n            \"formatter\": \"detailed\",\n            \"filename\": \"logs\/error.log\",\n            \"maxBytes\": 10485760,\n            \"backupCount\": 10,\n            \"encoding\": \"utf-8\"\n        }\n    },\n\n    \"loggers\": {\n        \"\": {  # root logger\n            \"level\": \"DEBUG\",\n            \"handlers\": [\"console\", \"file\", \"error_file\"],\n            \"propagate\": False\n        },\n        \"uvicorn\": {\n            \"level\": \"INFO\",\n            \"handlers\": [\"console\"],\n            \"propagate\": False\n        },\n        \"sqlalchemy.engine\": {\n            \"level\": \"WARNING\",\n            \"handlers\": [\"file\"],\n            \"propagate\": False\n        }\n    }\n}\n\nlogging.config.dictConfig(LOGGING_CONFIG)\n<\/pre>\n\n<h3>4.3 \u4ece\u6587\u4ef6\u52a0\u8f7d\u914d\u7f6e<\/h3>\n<pre class=\"code-block\">import logging.config\nimport json\n\n# JSON \u914d\u7f6e\u6587\u4ef6\nwith open(\"logging.json\", \"r\", encoding=\"utf-8\") as f:\n    config = json.load(f)\nlogging.config.dictConfig(config)\n\n# \u6216\u901a\u8fc7\u73af\u5883\u53d8\u91cf\u9009\u62e9\u914d\u7f6e\nimport os\nenv = os.getenv(\"ENV\", \"dev\")\nconfig_file = f\"config\/logging.{env}.json\"\nwith open(config_file, \"r\", encoding=\"utf-8\") as f:\n    logging.config.dictConfig(json.load(f))\n<\/pre>\n\n<!-- \u4e94\u3001\u65e5\u5fd7\u6587\u4ef6\u7ba1\u7406 -->\n<h2 id=\"zh-5\">\u4e94\u3001\u65e5\u5fd7\u6587\u4ef6\u7ba1\u7406\u7b56\u7565<\/h2>\n\n<h3>5.1 \u6587\u4ef6\u8f6e\u8f6c\u7b56\u7565\u5bf9\u6bd4<\/h3>\n<div class=\"table-wrap\">\n<table>\n  <thead>\n    <tr><th>Handler<\/th><th>\u8f6e\u8f6c\u6761\u4ef6<\/th><th>\u9002\u7528\u573a\u666f<\/th><th>\u6ce8\u610f\u70b9<\/th><\/tr>\n  <\/thead>\n  <tbody>\n    <tr><td>RotatingFileHandler<\/td><td>\u6587\u4ef6\u5927\u5c0f\u8fbe\u5230 maxBytes<\/td><td>\u6d41\u91cf\u7a33\u5b9a\u7684\u5e94\u7528<\/td><td>\u591a\u8fdb\u7a0b\u540c\u65f6\u5199\u5165\u53ef\u80fd\u4e22\u5931<\/td><\/tr>\n    <tr><td>TimedRotatingFileHandler<\/td><td>\u65f6\u95f4\u5230\u8fbe\uff08\u5929\/\u5c0f\u65f6\/\u5206\u949f\uff09<\/td><td>\u5b9a\u65f6\u5f52\u6863\u9700\u6c42<\/td><td>\u5348\u591c\u5207\u6362\u65f6\u6ce8\u610f\u65e5\u5fd7\u5f52\u5c5e<\/td><\/tr>\n    <tr><td>WatchedFileHandler<\/td><td>\u5916\u90e8\u5de5\u5177\u8f6e\u8f6c\u4fe1\u53f7<\/td><td>\u914d\u5408 logrotate \u4f7f\u7528<\/td><td>Linux \u7cfb\u7edf\u7ea7\u65e5\u5fd7\u7ba1\u7406<\/td><\/tr>\n    <tr><td>QueueHandler<\/td><td>\u5f02\u6b65\u961f\u5217<\/td><td>\u9ad8\u5e76\u53d1\u6027\u80fd\u573a\u666f<\/td><td>\u9700\u8981\u914d\u5408 QueueListener<\/td><\/tr>\n  <\/tbody>\n<\/table>\n<\/div>\n\n<h3>5.2 \u6309\u5927\u5c0f\u8f6e\u8f6c\u914d\u7f6e<\/h3>\n<pre class=\"code-block\">from logging.handlers import RotatingFileHandler\n\n# 10MB \u4e00\u4e2a\u6587\u4ef6\uff0c\u4fdd\u7559 5 \u4e2a\u5907\u4efd\nhandler = RotatingFileHandler(\n    \"app.log\",\n    maxBytes=10 * 1024 * 1024,  # 10MB\n    backupCount=5,\n    encoding=\"utf-8\"\n)\n# \u751f\u6210: app.log, app.log.1, app.log.2, ..., app.log.5\n<\/pre>\n\n<h3>5.3 \u6309\u65f6\u95f4\u8f6e\u8f6c\u914d\u7f6e<\/h3>\n<pre class=\"code-block\">from logging.handlers import TimedRotatingFileHandler\n\n# \u6bcf\u5929\u5348\u591c\u8f6e\u8f6c\uff0c\u4fdd\u7559 30 \u5929\nhandler = TimedRotatingFileHandler(\n    \"app.log\",\n    when=\"midnight\",      # \u53ef\u9009: S(\u79d2), M(\u5206), H(\u5c0f\u65f6), D(\u5929), W0-W6(\u5468\u51e0)\n    interval=1,\n    backupCount=30,\n    encoding=\"utf-8\"\n)\n# \u751f\u6210: app.log, app.log.2026-07-15, app.log.2026-07-14, ...\n<\/pre>\n\n<h3>5.4 \u914d\u5408 Linux logrotate<\/h3>\n<pre class=\"code-block\"># \/etc\/logrotate.d\/myapp\n\/var\/log\/myapp\/*.log {\n    daily\n    rotate 30\n    compress\n    delaycompress\n    missingok\n    notifempty\n    create 0644 www-data www-data\n    sharedscripts\n    postrotate\n        # \u901a\u77e5\u5e94\u7528\u91cd\u65b0\u6253\u5f00\u65e5\u5fd7\u6587\u4ef6\n        kill -USR1 $(cat \/var\/run\/myapp.pid)\n    endscript\n}\n<\/pre>\n\n<div class=\"info-box warn\">\n  <strong>\u591a\u8fdb\u7a0b\u573a\u666f\uff1a\u6807\u51c6 RotatingFileHandler \u4e0d\u652f\u6301\u591a\u8fdb\u7a0b\u5b89\u5168\u3002\u9ad8\u5e76\u53d1\u6216\u90e8\u7f72\u591a\u4e2a Worker \u65f6\uff0c\u5e94\u4f7f\u7528 concurrent-log-handler \u5e93\u6216\u91c7\u7528 SocketHandler + \u72ec\u7acb\u65e5\u5fd7\u8fdb\u7a0b\u3002<\/strong>\n<\/div>\n\n<!-- \u516d\u3001\u4e0d\u540c\u73af\u5883\u914d\u7f6e -->\n<h2 id=\"zh-6\">\u516d\u3001\u4e0d\u540c\u73af\u5883\u7684\u65e5\u5fd7\u914d\u7f6e<\/h2>\n\n<h3>6.1 \u73af\u5883\u914d\u7f6e\u5bf9\u7167<\/h3>\n<div class=\"two-col\">\n  <div class=\"col\">\n    <h4>\u5f00\u53d1\u73af\u5883\uff08dev\uff09<\/h4>\n    <pre class=\"example\">level: DEBUG\nhandlers: [console]\nformat: \u7b80\u6d01\uff0c\u5e26\u884c\u53f7\npropagate: True<\/pre>\n    <p>\u8f93\u51fa\u5230\u63a7\u5236\u53f0\uff0cDEBUG \u7ea7\u522b\u5168\u5f00\uff0c\u65b9\u4fbf\u8c03\u8bd5\u8ffd\u8e2a\u3002<\/p>\n  <\/div>\n  <div class=\"col\">\n    <h4>\u6d4b\u8bd5\u73af\u5883\uff08test\uff09<\/h4>\n    <pre class=\"example\">level: DEBUG\nhandlers: [console, file]\nformat: \u8be6\u7ec6\uff0c\u5e26\u51fd\u6570\u540d\npropagate: False<\/pre>\n    <p>\u540c\u65f6\u8f93\u51fa\u5230\u63a7\u5236\u53f0\u548c\u6587\u4ef6\uff0c\u65b9\u4fbf CI \u6536\u96c6\u65e5\u5fd7\u3002<\/p>\n  <\/div>\n<\/div>\n<div class=\"two-col\">\n  <div class=\"col\">\n    <h4>\u9884\u53d1\u5e03\u73af\u5883\uff08staging\uff09<\/h4>\n    <pre class=\"example\">level: INFO\nhandlers: [file, error_file]\nformat: JSON \u7ed3\u6784\u5316\npropagate: False<\/pre>\n    <p>\u63a5\u8fd1\u751f\u4ea7\u914d\u7f6e\uff0c\u4f7f\u7528 JSON \u683c\u5f0f\u5bf9\u63a5\u65e5\u5fd7\u6536\u96c6\u7cfb\u7edf\u3002<\/p>\n  <\/div>\n  <div class=\"col\">\n    <h4>\u751f\u4ea7\u73af\u5883\uff08prod\uff09<\/h4>\n    <pre class=\"example\">level: INFO\nhandlers: [file]\nformat: JSON \u7ed3\u6784\u5316\npropagate: False<\/pre>\n    <p>INFO \u53ca\u4ee5\u4e0a\u5199\u5165\u6587\u4ef6\uff0cERROR \u5355\u72ec\u5f52\u6863\uff0c\u7ed3\u6784\u5316\u8f93\u51fa\u3002<\/p>\n  <\/div>\n<\/div>\n\n<h3>6.2 \u73af\u5883\u5207\u6362\u5b9e\u73b0<\/h3>\n<pre class=\"code-block\">import logging.config\nimport os\n\ndef get_logging_config(env: str) -> dict:\n    \"\"\"\u6839\u636e\u73af\u5883\u8fd4\u56de\u65e5\u5fd7\u914d\u7f6e\u3002\"\"\"\n    base = {\n        \"version\": 1,\n        \"disable_existing_loggers\": False,\n        \"formatters\": {\n            \"simple\": {\"format\": \"%(levelname)s: %(message)s\"},\n            \"standard\": {\"format\": \"%(asctime)s [%(levelname)s] %(name)s - %(message)s\"},\n            \"json\": {\"class\": \"pythonjsonlogger.jsonlogger.JsonFormatter\",\n                     \"format\": \"%(asctime)s %(levelname)s %(name)s %(message)s\"}\n        },\n        \"handlers\": {},\n        \"loggers\": {}\n    }\n\n    if env == \"dev\":\n        base[\"handlers\"][\"console\"] = {\n            \"class\": \"logging.StreamHandler\",\n            \"level\": \"DEBUG\",\n            \"formatter\": \"standard\"\n        }\n        base[\"loggers\"][\"\"] = {\"level\": \"DEBUG\", \"handlers\": [\"console\"]}\n\n    elif env == \"prod\":\n        base[\"handlers\"][\"file\"] = {\n            \"class\": \"logging.handlers.TimedRotatingFileHandler\",\n            \"level\": \"INFO\",\n            \"formatter\": \"json\",\n            \"filename\": \"\/var\/log\/myapp\/app.log\",\n            \"when\": \"midnight\",\n            \"backupCount\": 30\n        }\n        base[\"handlers\"][\"error\"] = {\n            \"class\": \"logging.handlers.RotatingFileHandler\",\n            \"level\": \"ERROR\",\n            \"formatter\": \"json\",\n            \"filename\": \"\/var\/log\/myapp\/error.log\",\n            \"maxBytes\": 10485760,\n            \"backupCount\": 10\n        }\n        base[\"loggers\"][\"\"] = {\"level\": \"INFO\", \"handlers\": [\"file\", \"error\"]}\n\n    return base\n\n\nenv = os.getenv(\"ENV\", \"dev\")\nlogging.config.dictConfig(get_logging_config(env))\n<\/pre>\n\n<!-- \u4e03\u3001\u7ed3\u6784\u5316\u65e5\u5fd7 -->\n<h2 id=\"zh-7\">\u4e03\u3001\u7ed3\u6784\u5316\u65e5\u5fd7\u4e0e JSON \u8f93\u51fa<\/h2>\n\n<div class=\"info-box\">\n  <strong>\u7ed3\u6784\u5316\u65e5\u5fd7\u5c06\u65e5\u5fd7\u8f93\u51fa\u4e3a\u673a\u5668\u53ef\u89e3\u6790\u7684\u683c\u5f0f\uff08\u5982 JSON\uff09\uff0c\u4fbf\u4e8e\u65e5\u5fd7\u6536\u96c6\u7cfb\u7edf\uff08ELK\u3001Loki\u3001CloudWatch\uff09\u7d22\u5f15\u3001\u641c\u7d22\u548c\u805a\u5408\u5206\u6790\u3002<\/strong>\n<\/div>\n\n<h3>7.1 \u666e\u901a\u6587\u672c vs \u7ed3\u6784\u5316 JSON<\/h3>\n<div class=\"compare-box\">\n  <div class=\"compare-col bad\">\n    <h4>\u274c \u666e\u901a\u6587\u672c\u65e5\u5fd7<\/h4>\n<pre class=\"example\">2026-07-16 14:32:10 [INFO] myapp:231 - \n\u7528\u6237 12345 \u767b\u5f55\u6210\u529f\uff0cIP: 192.168.1.1\uff0c\u8017\u65f6: 45ms<\/pre>\n    <p>\u89e3\u6790\u56f0\u96be\uff0c\u9700\u8981\u6b63\u5219\u63d0\u53d6\u5b57\u6bb5\uff0c\u641c\u7d22\u6548\u7387\u4f4e\u3002<\/p>\n  <\/div>\n  <div class=\"compare-col good\">\n    <h4>\u2705 \u7ed3\u6784\u5316 JSON \u65e5\u5fd7<\/h4>\n<pre class=\"example\">{\"timestamp\":\"2026-07-16T14:32:10Z\",\n \"level\":\"INFO\",\n \"logger\":\"myapp.auth\",\n \"event\":\"user_login\",\n \"user_id\":\"12345\",\n \"client_ip\":\"192.168.1.1\",\n \"duration_ms\":45}<\/pre>\n    <p>\u5b57\u6bb5\u660e\u786e\uff0c\u53ef\u76f4\u63a5\u88ab Elasticsearch \u7b49\u7cfb\u7edf\u7d22\u5f15\u3002<\/p>\n  <\/div>\n<\/div>\n\n<h3>7.2 python-json-logger \u914d\u7f6e<\/h3>\n<pre class=\"code-block\"># pip install python-json-logger\n\nfrom pythonjsonlogger import jsonlogger\nimport logging\n\nlogHandler = logging.StreamHandler()\nformatter = jsonlogger.JsonFormatter(\n    \"%(asctime)s %(levelname)s %(name)s %(message)s\",\n    rename_fields={\"levelname\": \"level\", \"asctime\": \"timestamp\"}\n)\nlogHandler.setFormatter(formatter)\n\nlogger = logging.getLogger()\nlogger.addHandler(logHandler)\nlogger.setLevel(logging.INFO)\n\n# \u8f93\u51fa\u7ed3\u6784\u5316\u65e5\u5fd7\nlogger.info(\"\u7528\u6237\u767b\u5f55\", extra={\"user_id\": \"12345\", \"ip\": \"192.168.1.1\"})\n# {\"timestamp\": \"2026-07-16 14:32:10\", \"level\": \"INFO\", \"name\": \"root\",\n#  \"message\": \"\u7528\u6237\u767b\u5f55\", \"user_id\": \"12345\", \"ip\": \"192.168.1.1\"}\n<\/pre>\n\n<h3>7.3 \u7edf\u4e00\u65e5\u5fd7\u4e0a\u4e0b\u6587\uff08Context\uff09<\/h3>\n<pre class=\"code-block\">import logging\nimport contextvars\nimport uuid\n\n# \u4e0a\u4e0b\u6587\u53d8\u91cf\nrequest_id = contextvars.ContextVar(\"request_id\", default=\"\")\n\nclass ContextFilter(logging.Filter):\n    \"\"\"\u81ea\u52a8\u6ce8\u5165\u8bf7\u6c42 ID \u5230\u65e5\u5fd7\u8bb0\u5f55\u3002\"\"\"\n    def filter(self, record):\n        record.request_id = request_id.get()\n        return True\n\n# \u914d\u7f6e\nlogger = logging.getLogger(\"myapp\")\nlogger.addFilter(ContextFilter())\n\nformatter = logging.Formatter(\n    \"%(asctime)s [%(levelname)s] [%(request_id)s] %(message)s\"\n)\n\n# \u4f7f\u7528\nrequest_id.set(str(uuid.uuid4())[:8])\nlogger.info(\"\u5904\u7406\u8bf7\u6c42\u5f00\u59cb\")\nlogger.info(\"\u67e5\u8be2\u6570\u636e\u5e93\")\nlogger.info(\"\u8fd4\u56de\u54cd\u5e94\")\n# \u6240\u6709\u65e5\u5fd7\u81ea\u52a8\u643a\u5e26\u540c\u4e00\u4e2a request_id\uff0c\u4fbf\u4e8e\u94fe\u8def\u8ffd\u8e2a\n<\/pre>\n\n<!-- \u516b\u3001\u6027\u80fd\u4f18\u5316 -->\n<h2 id=\"zh-8\">\u516b\u3001\u6027\u80fd\u4f18\u5316\u4e0e\u5f02\u6b65\u65e5\u5fd7<\/h2>\n\n<h3>8.1 \u65e5\u5fd7\u6027\u80fd\u8981\u70b9<\/h3>\n<div class=\"card\">\n  <h4>\u6027\u80fd\u4f18\u5316\u539f\u5219<\/h4>\n  <p>1. <span class=\"tag tag-r\">\u5ef6\u8fdf\u683c\u5f0f\u5316<\/span> \u4f7f\u7528 <code>logger.debug(\"value: %s\", value)<\/code> \u800c\u975e <code>f\"value: {value}\"<\/code>\uff0c\u907f\u514d\u4e0d\u5fc5\u8981\u7684\u5b57\u7b26\u4e32\u62fc\u63a5<\/p>\n  <p>2. <span class=\"tag tag-b\">\u7ea7\u522b\u68c0\u67e5<\/span> DEBUG \u65e5\u5fd7\u5bc6\u96c6\u573a\u666f\u4f7f\u7528 <code>if logger.isEnabledFor(logging.DEBUG)<\/code> \u63d0\u524d\u5224\u65ad<\/p>\n  <p>3. <span class=\"tag tag-g\">\u5f02\u6b65\u5199\u5165<\/span> \u9ad8\u5e76\u53d1\u573a\u666f\u4f7f\u7528 QueueHandler \u907f\u514d\u963b\u585e\u4e3b\u7ebf\u7a0b<\/p>\n  <p>4. <span class=\"tag tag-y\">\u6279\u91cf\u5237\u65b0<\/span> \u6587\u4ef6 Handler \u8bbe\u7f6e\u5408\u7406\u7684 buffer size\uff0c\u51cf\u5c11 IO \u6b21\u6570<\/p>\n<\/div>\n\n<h3>8.2 QueueHandler \u5f02\u6b65\u914d\u7f6e<\/h3>\n<pre class=\"code-block\">import logging\nimport logging.handlers\nimport queue\n\n# \u521b\u5efa\u65e5\u5fd7\u961f\u5217\nlog_queue = queue.Queue(-1)  # \u65e0\u754c\u961f\u5217\n\n# \u961f\u5217 Handler\uff08\u751f\u4ea7\u8005\uff09\nqueue_handler = logging.handlers.QueueHandler(log_queue)\n\n# \u5b9e\u9645\u5199\u5165 Handler\uff08\u6d88\u8d39\u8005\uff09\nfile_handler = logging.FileHandler(\"app.log\", encoding=\"utf-8\")\nfile_handler.setFormatter(logging.Formatter(\n    \"%(asctime)s [%(levelname)s] %(message)s\"\n))\n\n# \u961f\u5217\u76d1\u542c\u5668\uff0c\u5728\u72ec\u7acb\u7ebf\u7a0b\u4e2d\u6d88\u8d39\u65e5\u5fd7\nlistener = logging.handlers.QueueListener(\n    log_queue, file_handler, respect_handler_level=True\n)\n\n# \u914d\u7f6e\u6839 Logger\nroot = logging.getLogger()\nroot.addHandler(queue_handler)\nroot.setLevel(logging.DEBUG)\n\n# \u542f\u52a8\u76d1\u542c\u5668\nlistener.start()\n\n# ... \u5e94\u7528\u8fd0\u884c ...\n\n# \u5173\u95ed\u65f6\u505c\u6b62\u76d1\u542c\u5668\nlistener.stop()\n<\/pre>\n\n<!-- \u4e5d\u3001\u65e5\u5fd7\u5b89\u5168 -->\n<h2 id=\"zh-9\">\u4e5d\u3001\u65e5\u5fd7\u5b89\u5168\u4e0e\u654f\u611f\u4fe1\u606f\u5904\u7406<\/h2>\n\n<h3>9.1 \u654f\u611f\u4fe1\u606f\u7ea2\u7ebf<\/h3>\n<div class=\"info-box danger\">\n  <strong>\u7edd\u5bf9\u7981\u6b62\u5199\u5165\u65e5\u5fd7\u7684\u5185\u5bb9\uff1a\u5bc6\u7801\u3001Token\u3001API Key\u3001\u94f6\u884c\u5361\u53f7\u3001\u8eab\u4efd\u8bc1\u53f7\u3001\u624b\u673a\u53f7\u3001Session Cookie\u3001\u4e2a\u4eba\u9690\u79c1\u6570\u636e\u3002\u65e5\u5fd7\u6cc4\u9732\u662f\u5e38\u89c1\u7684\u5b89\u5168\u4e8b\u6545\u6765\u6e90\u3002<\/strong>\n<\/div>\n\n<h3>9.2 \u654f\u611f\u4fe1\u606f\u8131\u654f<\/h3>\n<pre class=\"code-block\">import logging\nimport re\n\nclass SensitiveDataFilter(logging.Filter):\n    \"\"\"\u65e5\u5fd7\u654f\u611f\u4fe1\u606f\u8131\u654f\u8fc7\u6ee4\u5668\u3002\"\"\"\n\n    PATTERNS = {\n        \"password\": re.compile(r'(\"password\"\\s*:\\s*\")[^\"]*(\"', re.I),\n        \"token\": re.compile(r'(Bearer\\s+)[\\w\\-\\.]+', re.I),\n        \"phone\": re.compile(r'(1\\d{2})\\d{4}(\\d{4})'),\n        \"id_card\": re.compile(r'(\\d{6})\\d{8}(\\d{4})'),\n    }\n\n    def filter(self, record):\n        msg = record.getMessage()\n        for name, pattern in self.PATTERNS.items():\n            if name in (\"password\", \"token\"):\n                msg = pattern.sub(r'\\1***\\2', msg)\n            else:\n                msg = pattern.sub(r'\\1****\\2', msg)\n        record.msg = msg\n        record.args = ()\n        return True\n\n# \u5e94\u7528\u8fc7\u6ee4\u5668\nlogger = logging.getLogger(\"myapp\")\nlogger.addFilter(SensitiveDataFilter())\n\n# \u6d4b\u8bd5\nlogger.info('\u767b\u5f55\u8bf7\u6c42: {\"username\":\"alice\",\"password\":\"Secret123\"}')\n# \u8f93\u51fa: \u767b\u5f55\u8bf7\u6c42: {\"username\":\"alice\",\"password\":\"***\"}\n<\/pre>\n\n<h3>9.3 \u5b89\u5168\u7684\u65e5\u5fd7\u8bb0\u5f55\u5b9e\u8df5<\/h3>\n<pre class=\"code-block\"># \u274c \u9519\u8bef\uff1a\u8bb0\u5f55\u654f\u611f\u4fe1\u606f\nlogger.info(f\"\u7528\u6237\u767b\u5f55: {username}, \u5bc6\u7801: {password}\")\nlogger.debug(f\"API \u8bf7\u6c42\u5934: {headers}\")  # \u53ef\u80fd\u5305\u542b Token\n\n# \u2705 \u6b63\u786e\uff1a\u8131\u654f\u540e\u8bb0\u5f55\nlogger.info(f\"\u7528\u6237\u767b\u5f55: {username}\")\nlogger.debug(f\"API \u8bf7\u6c42\u5934 keys: {list(headers.keys())}\")\n\n# \u2705 \u6b63\u786e\uff1a\u53ea\u8bb0\u5f55\u5fc5\u8981\u7684\u6807\u8bc6\nlogger.info(f\"\u652f\u4ed8\u8bf7\u6c42: order_id={order_id}, amount={amount}\")\n# \u4e0d\u8981\u8bb0\u5f55: card_number, cvv, \u6301\u5361\u4eba\u59d3\u540d\n<\/pre>\n\n<!-- \u5341\u3001\u5e38\u89c1\u95ee\u9898 -->\n<h2 id=\"zh-10\">\u5341\u3001\u5e38\u89c1\u95ee\u9898\u4e0e\u6392\u67e5\u6a21\u677f<\/h2>\n\n<div class=\"table-wrap\">\n<table>\n  <thead>\n    <tr><th>\u95ee\u9898\u73b0\u8c61<\/th><th>\u539f\u56e0<\/th><th>\u89e3\u51b3\u65b9\u6848<\/th><\/tr>\n  <\/thead>\n  <tbody>\n    <tr>\n      <td>\u65e5\u5fd7\u4e0d\u8f93\u51fa<\/td>\n      <td>Logger\/Handler \u7ea7\u522b\u8bbe\u7f6e\u8fc7\u9ad8\uff0c\u6216 propagate=False \u4e14\u672a\u914d\u7f6e Handler<\/td>\n      <td>\u68c0\u67e5 logger.level\u3001handler.level\u3001\u786e\u8ba4\u6709 Handler \u9644\u52a0<\/td>\n    <\/tr>\n    <tr>\n      <td>\u65e5\u5fd7\u91cd\u590d\u8f93\u51fa<\/td>\n      <td>\u5b50 Logger \u548c\u6839 Logger \u90fd\u6709 Handler\uff0cpropagate=True<\/td>\n      <td>\u5b50 Logger \u8bbe\u7f6e propagate=False\uff0c\u6216\u79fb\u9664\u91cd\u590d\u7684 Handler<\/td>\n    <\/tr>\n    <tr>\n      <td>\u4e2d\u6587\u65e5\u5fd7\u4e71\u7801<\/td>\n      <td>FileHandler \u672a\u8bbe\u7f6e encoding=&#8221;utf-8&#8243;<\/td>\n      <td>\u6240\u6709 FileHandler \u663e\u5f0f\u8bbe\u7f6e encoding=&#8221;utf-8&#8243;<\/td>\n    <\/tr>\n    <tr>\n      <td>\u65e5\u5fd7\u6587\u4ef6\u4e0d\u8f6e\u8f6c<\/td>\n      <td>\u591a\u8fdb\u7a0b\u4e0b RotatingFileHandler \u7ade\u4e89\u5199\u5165<\/td>\n      <td>\u4f7f\u7528 concurrent-log-handler\uff0c\u6216\u6539\u7528 TimedRotatingFileHandler<\/td>\n    <\/tr>\n    <tr>\n      <td>\u65e5\u5fd7\u4e22\u5931<\/td>\n      <td>\u7a0b\u5e8f\u5d29\u6e83\u524d\u65e5\u5fd7\u672a flush \u5230\u78c1\u76d8<\/td>\n      <td>\u5173\u952e\u4f4d\u7f6e\u8c03\u7528 logging.shutdown()\uff0c\u6216\u8bbe\u7f6e stream.flush()<\/td>\n    <\/tr>\n    <tr>\n      <td>\u7b2c\u4e09\u65b9\u5e93\u65e5\u5fd7\u592a\u591a<\/td>\n      <td>urllib3\u3001sqlalchemy \u7b49\u5e93\u9ed8\u8ba4\u7ea7\u522b\u4f4e<\/td>\n      <td>\u5355\u72ec\u914d\u7f6e\u7b2c\u4e09\u65b9 Logger: logging.getLogger(&#8220;urllib3&#8221;).setLevel(logging.WARNING)<\/td>\n    <\/tr>\n    <tr>\n      <td>\u65e5\u5fd7\u963b\u585e\u4e3b\u7ebf\u7a0b<\/td>\n      <td>\u540c\u6b65\u6587\u4ef6 IO\uff0c\u9ad8\u5e76\u53d1\u4e0b\u6027\u80fd\u74f6\u9888<\/td>\n      <td>\u4f7f\u7528 QueueHandler + QueueListener \u5b9e\u73b0\u5f02\u6b65\u65e5\u5fd7<\/td>\n    <\/tr>\n  <\/tbody>\n<\/table>\n<\/div>\n\n<h3>\u6392\u67e5\u68c0\u67e5\u6e05\u5355<\/h3>\n<pre class=\"code-block\"># 1. \u68c0\u67e5 Logger \u5c42\u7ea7\u548c\u7ea7\u522b\nfor name in [\"\", \"myapp\", \"myapp.api\"]:\n    logger = logging.getLogger(name)\n    print(f\"{name}: level={logger.level}, handlers={logger.handlers}, propagate={logger.propagate}\")\n\n# 2. \u68c0\u67e5\u6240\u6709 Handler\nfor handler in logging.getLogger().handlers:\n    print(f\"Handler: {handler}, level={handler.level}, formatter={handler.formatter}\")\n\n# 3. \u5f3a\u5236\u8f93\u51fa\u6d4b\u8bd5\nlogging.getLogger().debug(\"debug test\")\nlogging.getLogger().info(\"info test\")\nlogging.getLogger().warning(\"warning test\")\n<\/pre>\n\n<div class=\"info-box\">\n  <strong>\u5168\u6d41\u7a0b\u603b\u7ed3\uff1a\u7406\u89e3\u65e5\u5fd7\u5c42\u7ea7\uff08DEBUG\u2192CRITICAL\uff09\u2192 \u6839\u636e\u73af\u5883\u9009\u62e9\u5408\u9002\u7684\u7ea7\u522b \u2192 \u4f7f\u7528 dictConfig \u7edf\u4e00\u7ba1\u7406\u914d\u7f6e \u2192 \u6587\u4ef6\u8f6e\u8f6c\u907f\u514d\u78c1\u76d8\u6253\u6ee1 \u2192 \u751f\u4ea7\u73af\u5883\u4f7f\u7528 JSON \u7ed3\u6784\u5316\u65e5\u5fd7 \u2192 \u654f\u611f\u4fe1\u606f\u8131\u654f\u5904\u7406 \u2192 \u9ad8\u5e76\u53d1\u573a\u666f\u4f7f\u7528\u5f02\u6b65 QueueHandler \u2192 \u914d\u5408\u65e5\u5fd7\u6536\u96c6\u7cfb\u7edf\u5b9e\u73b0\u96c6\u4e2d\u76d1\u63a7\u3002<\/strong>\n<\/div>\n\n<\/div>\n\n<!-- ======== \u82f1\u6587\u7248 ======== -->\n<div class=\"lang-section\" id=\"lang-en\">\n<div class=\"hero\">\n  <h1>Python Logging Complete Guide<span class=\"sub\">Levels \u2192 Configuration \u2192 Production Best Practices<\/span><\/h1>\n  <p>Logging levels deep dive, logging module architecture, Handler &#038; Formatter, file management, structured logs, performance, environment-specific configs<\/p>\n<\/div>\n\n<div class=\"toc\">\n  <h3>Table of Contents<\/h3>\n  <ol>\n    <li><a href=\"#en-1\">1 Why Logging Matters<\/a><\/li>\n    <li><a href=\"#en-2\">2 Logging Levels Deep Dive<\/a><\/li>\n    <li><a href=\"#en-3\">3 Python logging Architecture<\/a><\/li>\n    <li><a href=\"#en-4\">4 Configuring Logging<\/a><\/li>\n    <li><a href=\"#en-5\">5 Log File Management<\/a><\/li>\n    <li><a href=\"#en-6\">6 Environment-Specific Configs<\/a><\/li>\n    <li><a href=\"#en-7\">7 Structured &#038; JSON Logging<\/a><\/li>\n    <li><a href=\"#en-8\">8 Performance &#038; Async Logging<\/a><\/li>\n    <li><a href=\"#en-9\">9 Security &#038; Sensitive Data<\/a><\/li>\n    <li><a href=\"#en-10\">10 FAQ &#038; Troubleshooting<\/a><\/li>\n  <\/ol>\n<\/div>\n\n<h2 id=\"en-1\">1 Why Logging Matters<\/h2>\n\n<div class=\"card\">\n  <h4>Five Core Values of Logging<\/h4>\n  <p><span class=\"tag tag-r\">Troubleshooting<\/span> Root cause analysis in production<\/p>\n  <p><span class=\"tag tag-b\">Audit Trail<\/span> Record user actions and data changes<\/p>\n  <p><span class=\"tag tag-g\">Performance<\/span> Identify bottlenecks via timing logs<\/p>\n  <p><span class=\"tag tag-y\">Monitoring<\/span> Track API calls, error rates, throughput<\/p>\n  <p><span class=\"tag tag-p\">Debugging<\/span> Trace execution flow during development<\/p>\n<\/div>\n\n<h2 id=\"en-2\">2 Logging Levels Deep Dive<\/h2>\n\n<div class=\"table-wrap\">\n<table>\n  <thead>\n    <tr><th>Level<\/th><th>Value<\/th><th>Meaning<\/th><th>Use Case<\/th><th>Production<\/th><\/tr>\n  <\/thead>\n  <tbody>\n    <tr><td><span class=\"tag tag-p\">DEBUG<\/span><\/td><td>10<\/td><td>Debug info<\/td><td>Variables, function params<\/td><td>Off<\/td><\/tr>\n    <tr><td><span class=\"tag tag-b\">INFO<\/span><\/td><td>20<\/td><td>General info<\/td><td>Service start, requests<\/td><td>On<\/td><\/tr>\n    <tr><td><span class=\"tag tag-y\">WARNING<\/span><\/td><td>30<\/td><td>Warning<\/td><td>Resource low, retries<\/td><td>On<\/td><\/tr>\n    <tr><td><span class=\"tag tag-r\">ERROR<\/span><\/td><td>40<\/td><td>Error<\/td><td>Failures, exceptions<\/td><td>On<\/td><\/tr>\n    <tr><td><span class=\"tag tag-r\" style=\"background:#991b1b;color:#fff\">CRITICAL<\/span><\/td><td>50<\/td><td>Critical<\/td><td>System crash, data loss<\/td><td>On<\/td><\/tr>\n  <\/tbody>\n<\/table>\n<\/div>\n\n<h3>Level Filtering Flow<\/h3>\n<div class=\"flow-diagram\">\n  <div class=\"flow-row\">\n    <span class=\"flow-item green\">Log emitted<\/span>\n    <span class=\"flow-arrow\">&rarr;<\/span>\n    <span class=\"flow-item\">Logger level filter<\/span>\n    <span class=\"flow-arrow\">&rarr;<\/span>\n    <span class=\"flow-item yellow\">Handler level filter<\/span>\n    <span class=\"flow-arrow\">&rarr;<\/span>\n    <span class=\"flow-item purple\">Formatter<\/span>\n    <span class=\"flow-arrow\">&rarr;<\/span>\n    <span class=\"flow-item green\">Output<\/span>\n  <\/div>\n<\/div>\n\n<h2 id=\"en-3\">3 Python logging Architecture<\/h2>\n\n<pre class=\"code-block\">Logger (hierarchical namespace)\n  \u251c\u2500\u2500 \"myapp.api.auth\" inherits \"myapp.api\"\n  \u251c\u2500\u2500 setLevel() \u2014 minimum accepted level\n  \u251c\u2500\u2500 propagate \u2014 pass to parent logger\n  \u2514\u2500\u2500 Handlers\n        \u251c\u2500\u2500 StreamHandler \u2192 console\n        \u251c\u2500\u2500 FileHandler \u2192 file\n        \u251c\u2500\u2500 RotatingFileHandler \u2192 size-based rotation\n        \u2514\u2500\u2500 TimedRotatingFileHandler \u2192 time-based rotation\n              \u2514\u2500\u2500 Formatter: \"%(asctime)s [%(levelname)s] %(message)s\"\n<\/pre>\n\n<h2 id=\"en-4\">4 Configuring Logging<\/h2>\n\n<h3>dictConfig (Recommended)<\/h3>\n<pre class=\"code-block\">LOGGING_CONFIG = {\n    \"version\": 1,\n    \"formatters\": {\n        \"standard\": {\n            \"format\": \"%(asctime)s [%(levelname)-8s] %(name)s - %(message)s\"\n        }\n    },\n    \"handlers\": {\n        \"console\": {\n            \"class\": \"logging.StreamHandler\",\n            \"level\": \"INFO\",\n            \"formatter\": \"standard\"\n        },\n        \"file\": {\n            \"class\": \"logging.handlers.RotatingFileHandler\",\n            \"level\": \"DEBUG\",\n            \"formatter\": \"standard\",\n            \"filename\": \"app.log\",\n            \"maxBytes\": 10485760,\n            \"backupCount\": 5\n        }\n    },\n    \"loggers\": {\n        \"\": {\"level\": \"DEBUG\", \"handlers\": [\"console\", \"file\"]}\n    }\n}\n\nlogging.config.dictConfig(LOGGING_CONFIG)\n<\/pre>\n\n<h2 id=\"en-5\">5 Log File Management<\/h2>\n\n<h3>Rotation Strategies<\/h3>\n<div class=\"table-wrap\">\n<table>\n  <thead><tr><th>Handler<\/th><th>Trigger<\/th><th>Use Case<\/th><\/tr><\/thead>\n  <tbody>\n    <tr><td>RotatingFileHandler<\/td><td>File size<\/td><td>Stable traffic apps<\/td><\/tr>\n    <tr><td>TimedRotatingFileHandler<\/td><td>Time (day\/hour)<\/td><td>Scheduled archiving<\/td><\/tr>\n    <tr><td>WatchedFileHandler<\/td><td>External signal<\/td><td>Linux logrotate<\/td><\/tr>\n    <tr><td>QueueHandler<\/td><td>Async queue<\/td><td>High concurrency<\/td><\/tr>\n  <\/tbody>\n<\/table>\n<\/div>\n\n<pre class=\"code-block\"># Size-based rotation: 10MB per file, keep 5 backups\nRotatingFileHandler(\"app.log\", maxBytes=10*1024*1024, backupCount=5)\n\n# Time-based rotation: daily at midnight, keep 30 days\nTimedRotatingFileHandler(\"app.log\", when=\"midnight\", backupCount=30)\n<\/pre>\n\n<h2 id=\"en-6\">6 Environment-Specific Configs<\/h2>\n\n<div class=\"two-col\">\n  <div class=\"col\">\n    <h4>Development<\/h4>\n    <pre class=\"example\">level: DEBUG\nhandlers: [console]\nformat: simple with line numbers<\/pre>\n  <\/div>\n  <div class=\"col\">\n    <h4>Production<\/h4>\n    <pre class=\"example\">level: INFO\nhandlers: [file]\nformat: JSON structured\nrotation: daily<\/pre>\n  <\/div>\n<\/div>\n\n<h2 id=\"en-7\">7 Structured &#038; JSON Logging<\/h2>\n\n<pre class=\"code-block\"># pip install python-json-logger\nfrom pythonjsonlogger import jsonlogger\n\nformatter = jsonlogger.JsonFormatter(\n    \"%(asctime)s %(levelname)s %(name)s %(message)s\",\n    rename_fields={\"levelname\": \"level\"}\n)\n\n# Output:\n# {\"timestamp\": \"2026-07-16T14:32:10\", \"level\": \"INFO\",\n#  \"name\": \"myapp\", \"message\": \"user login\", \"user_id\": \"12345\"}\n<\/pre>\n\n<h2 id=\"en-8\">8 Performance &#038; Async Logging<\/h2>\n\n<div class=\"card\">\n  <h4>Performance Tips<\/h4>\n  <p>1. <span class=\"tag tag-r\">Lazy formatting<\/span> Use <code>logger.debug(\"val: %s\", val)<\/code> not <code>f\"val: {val}\"<\/code><\/p>\n  <p>2. <span class=\"tag tag-b\">Level guard<\/span> Use <code>logger.isEnabledFor(logging.DEBUG)<\/code> for heavy debug logs<\/p>\n  <p>3. <span class=\"tag tag-g\">Async write<\/span> Use QueueHandler to avoid blocking main thread<\/p>\n<\/div>\n\n<h2 id=\"en-9\">9 Security &#038; Sensitive Data<\/h2>\n\n<div class=\"info-box danger\">\n  <strong>Never log: passwords, tokens, API keys, credit cards, ID numbers, phone numbers, session cookies, personal data. Log leakage is a common security incident.<\/strong>\n<\/div>\n\n<pre class=\"code-block\"># \u274c Wrong\nlogger.info(f\"Login: {username}, password: {password}\")\n\n# \u2705 Correct\nlogger.info(f\"Login: {username}\")\nlogger.debug(f\"Header keys: {list(headers.keys())}\")\n<\/pre>\n\n<h2 id=\"en-10\">10 FAQ &#038; Troubleshooting<\/h2>\n\n<div class=\"table-wrap\">\n<table>\n  <thead><tr><th>Issue<\/th><th>Solution<\/th><\/tr><\/thead>\n  <tbody>\n    <tr><td>No output<\/td><td>Check logger.level, handler.level, ensure handler attached<\/td><\/tr>\n    <tr><td>Duplicate output<\/td><td>Set propagate=False on child loggers<\/td><\/tr>\n    <tr><td>Chinese garbled<\/td><td>Set encoding=&#8221;utf-8&#8243; on all FileHandlers<\/td><\/tr>\n    <tr><td>Rotation not working<\/td><td>Use concurrent-log-handler for multi-process<\/td><\/tr>\n    <tr><td>Logs lost on crash<\/td><td>Call logging.shutdown() or flush handlers<\/td><\/tr>\n    <tr><td>Too many 3rd-party logs<\/td><td>Set urllib3\/sqlalchemy loggers to WARNING<\/td><\/tr>\n  <\/tbody>\n<\/table>\n<\/div>\n\n<div class=\"info-box\">\n  <strong>Summary: Understand logging levels (DEBUG\u2192CRITICAL) \u2192 Choose levels per environment \u2192 Use dictConfig for unified config \u2192 Rotate files to prevent disk fill \u2192 Use JSON structured logs in production \u2192 Sanitize sensitive data \u2192 Use QueueHandler for high concurrency \u2192 Integrate with centralized log collection.<\/strong>\n<\/div>\n\n<\/div>\n<\/main>\n\n<footer>\n  <div class=\"links\">\n    <a href=\"https:\/\/docs.python.org\/3\/library\/logging.html\" target=\"_blank\" rel=\"noopener\">Python logging Docs<\/a>\n    <a href=\"https:\/\/docs.python.org\/3\/howto\/logging.html\" target=\"_blank\" rel=\"noopener\">Logging HOWTO<\/a>\n    <a href=\"https:\/\/docs.python.org\/3\/howto\/logging-cookbook.html\" target=\"_blank\" rel=\"noopener\">Logging Cookbook<\/a>\n  <\/div>\n  <p>Python Logging Full Guide<\/p>\n<\/footer>\n\n<script>\nfunction setLang(lang){\n  document.querySelectorAll('.lang-section').forEach(el=>el.classList.remove('active'));\n  document.getElementById('lang-'+lang).classList.add('active');\n  document.querySelectorAll('.lang-switch button').forEach(btn=>btn.classList.remove('active'));\n  document.getElementById('btn-'+lang).classList.add('active');\n  document.documentElement.lang = lang==='zh'?'zh-CN':'en';\n  const prefix = lang==='zh'?'zh':'en';\n  const newHash = window.location.hash.replace(\/^#(zh|en)-\/, prefix+\"-\");\n  if(newHash) window.location.hash = newHash;\n}\nfunction toggleTheme(){\n  const html = document.documentElement;\n  if(html.hasAttribute('data-theme')){\n    html.removeAttribute('data-theme');\n    localStorage.removeItem('theme');\n  }else{\n    html.setAttribute('data-theme','dark');\n    localStorage.setItem('theme','dark');\n  }\n}\n(function(){\n  if(localStorage.getItem('theme')==='dark') document.documentElement.setAttribute('data-theme','dark');\n  const hash = window.location.hash;\n  if(hash){\n    const target = document.querySelector(hash);\n    if(target) setTimeout(()=>target.scrollIntoView({behavior:'smooth'}),100);\n  }\n})();\n<\/script>\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>Python \u65e5\u5fd7\u7ba1\u7406\u5b8c\u6574\u6307\u5357 \u00b7 Python Logging Full Guide \ud83d\udcdd Python \u65e5\u5fd7 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11,9],"tags":[],"class_list":["post-359","post","type-post","status-publish","format-standard","hentry","category-cad","category-ai"],"blocksy_meta":[],"_links":{"self":[{"href":"https:\/\/numsimlab.com\/index.php?rest_route=\/wp\/v2\/posts\/359","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/numsimlab.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/numsimlab.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/numsimlab.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/numsimlab.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=359"}],"version-history":[{"count":1,"href":"https:\/\/numsimlab.com\/index.php?rest_route=\/wp\/v2\/posts\/359\/revisions"}],"predecessor-version":[{"id":360,"href":"https:\/\/numsimlab.com\/index.php?rest_route=\/wp\/v2\/posts\/359\/revisions\/360"}],"wp:attachment":[{"href":"https:\/\/numsimlab.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=359"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/numsimlab.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=359"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/numsimlab.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=359"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}