{"id":10021266,"date":"2026-02-21T21:22:44","date_gmt":"2026-02-21T13:22:44","guid":{"rendered":"https:\/\/itmax.cn\/?p=10021266"},"modified":"2026-02-21T21:22:44","modified_gmt":"2026-02-21T13:22:44","slug":"python%e6%97%a5%e5%bf%97%e7%b3%bb%e7%bb%9f%e6%9e%b6%e6%9e%84%e8%ae%be%e8%ae%a1%e4%b8%8eelk%e9%9b%86%e6%88%90","status":"publish","type":"post","link":"https:\/\/itmax.cn\/?p=10021266","title":{"rendered":"Python\u65e5\u5fd7\u7cfb\u7edf\u67b6\u6784\u8bbe\u8ba1\u4e0eELK\u96c6\u6210"},"content":{"rendered":"<h2>Python\u65e5\u5fd7\u7cfb\u7edf\u67b6\u6784\u8bbe\u8ba1\u4e0eELK\u96c6\u6210<\/h2>\n<p>\u65e5\u5fd7\u662f\u7cfb\u7edf\u53ef\u89c2\u6d4b\u6027\u7684\u91cd\u8981\u7ec4\u6210\u90e8\u5206\u3002\u672c\u6587\u5c06\u4ecb\u7ecdPython\u65e5\u5fd7\u7cfb\u7edf\u67b6\u6784\u8bbe\u8ba1\u548cELK\u96c6\u6210\u65b9\u6848\u3002<\/p>\n<h3>\u65e5\u5fd7\u7cfb\u7edf\u6838\u5fc3\u7ec4\u4ef6<\/h3>\n<ul>\n<li><strong>Logger<\/strong>\uff1a\u65e5\u5fd7\u8bb0\u5f55\u5668<\/li>\n<li><strong>Handler<\/strong>\uff1a\u65e5\u5fd7\u5904\u7406\u5668<\/li>\n<li><strong>Formatter<\/strong>\uff1a\u65e5\u5fd7\u683c\u5f0f\u5316\u5668<\/li>\n<li><strong>Filter<\/strong>\uff1a\u65e5\u5fd7\u8fc7\u6ee4\u5668<\/li>\n<\/ul>\n<h3>\u65e5\u5fd7\u7cfb\u7edf\u6838\u5fc3\u5b9e\u73b0<\/h3>\n<pre><code class=\"python\">&quot;&quot;&quot;\nPython\u65e5\u5fd7\u7cfb\u7edf\u67b6\u6784\u8bbe\u8ba1\u4e0eELK\u96c6\u6210\n\u5305\u542b\u7ed3\u6784\u5316\u65e5\u5fd7\u3001\u591a\u5904\u7406\u5668\u3001ELK\u96c6\u6210\u7b49\n&quot;&quot;&quot;\n\nimport logging\nimport logging.handlers\nimport json\nimport sys\nfrom datetime import datetime\nfrom typing import Dict, Any, Optional\nfrom pythonjsonlogger import jsonlogger\nimport queue\nimport threading\n\n\n# ============ \u7ed3\u6784\u5316\u65e5\u5fd7\u683c\u5f0f ============\nclass StructuredLogFormatter(jsonlogger.JsonFormatter):\n    &quot;&quot;&quot;\u7ed3\u6784\u5316\u65e5\u5fd7\u683c\u5f0f\u5316\u5668&quot;&quot;&quot;\n    \n    def add_fields(self, log_record, record, message_dict):\n        super().add_fields(log_record, record, message_dict)\n        \n        # \u6dfb\u52a0\u65f6\u95f4\u6233\n        if not log_record.get('timestamp'):\n            log_record['timestamp'] = datetime.utcnow().isoformat()\n        \n        # \u6dfb\u52a0\u65e5\u5fd7\u7ea7\u522b\n        if log_record.get('level'):\n            log_record['level'] = log_record['level'].upper()\n        else:\n            log_record['level'] = record.levelname\n        \n        # \u6dfb\u52a0\u6e90\u4fe1\u606f\n        log_record['source'] = {\n            'file': record.filename,\n            'line': record.lineno,\n            'function': record.funcName,\n            'module': record.module\n        }\n\n\n# ============ \u81ea\u5b9a\u4e49\u65e5\u5fd7\u5904\u7406\u5668 ============\nclass AsyncHandler(logging.Handler):\n    &quot;&quot;&quot;\u5f02\u6b65\u65e5\u5fd7\u5904\u7406\u5668&quot;&quot;&quot;\n    \n    def __init__(self, handler: logging.Handler, max_queue_size: int = 1000):\n        super().__init__()\n        self.handler = handler\n        self.queue = queue.Queue(maxsize=max_queue_size)\n        self.thread = threading.Thread(target=self._process, daemon=True)\n        self.thread.start()\n    \n    def emit(self, record):\n        try:\n            self.queue.put_nowait(record)\n        except queue.Full:\n            # \u961f\u5217\u6ee1\u65f6\u76f4\u63a5\u5904\u7406\n            self.handler.emit(record)\n    \n    def _process(self):\n        while True:\n            try:\n                record = self.queue.get()\n                if record is None:\n                    break\n                self.handler.emit(record)\n            except Exception:\n                pass\n    \n    def close(self):\n        self.queue.put(None)\n        self.thread.join(timeout=5)\n        self.handler.close()\n        super().close()\n\n\nclass ContextFilter(logging.Filter):\n    &quot;&quot;&quot;\u4e0a\u4e0b\u6587\u8fc7\u6ee4\u5668&quot;&quot;&quot;\n    \n    def __init__(self, context: Dict[str, Any] = None):\n        super().__init__()\n        self.context = context or {}\n        self._local = threading.local()\n    \n    def filter(self, record):\n        # \u6dfb\u52a0\u4e0a\u4e0b\u6587\u4fe1\u606f\n        for key, value in self.context.items():\n            setattr(record, key, value)\n        \n        # \u6dfb\u52a0\u7ebf\u7a0b\u672c\u5730\u4e0a\u4e0b\u6587\n        if hasattr(self._local, 'request_id'):\n            record.request_id = self._local.request_id\n        \n        return True\n    \n    def set_request_id(self, request_id: str):\n        self._local.request_id = request_id\n\n\n# ============ \u65e5\u5fd7\u914d\u7f6e ============\ndef setup_logging(\n    level: str = &quot;INFO&quot;,\n    log_file: Optional[str] = None,\n    json_format: bool = True\n) -&gt; logging.Logger:\n    &quot;&quot;&quot;\u914d\u7f6e\u65e5\u5fd7\u7cfb\u7edf&quot;&quot;&quot;\n    \n    # \u521b\u5efalogger\n    logger = logging.getLogger(&quot;app&quot;)\n    logger.setLevel(getattr(logging, level.upper()))\n    logger.handlers = []  # \u6e05\u9664\u73b0\u6709\u5904\u7406\u5668\n    \n    # \u521b\u5efa\u683c\u5f0f\u5316\u5668\n    if json_format:\n        formatter = StructuredLogFormatter(\n            '%(timestamp)s %(level)s %(name)s %(message)s'\n        )\n    else:\n        formatter = logging.Formatter(\n            '%(asctime)s - %(name)s - %(levelname)s - %(message)s'\n        )\n    \n    # \u63a7\u5236\u53f0\u5904\u7406\u5668\n    console_handler = logging.StreamHandler(sys.stdout)\n    console_handler.setFormatter(formatter)\n    logger.addHandler(console_handler)\n    \n    # \u6587\u4ef6\u5904\u7406\u5668\n    if log_file:\n        file_handler = logging.handlers.RotatingFileHandler(\n            log_file,\n            maxBytes=10*1024*1024,  # 10MB\n            backupCount=5\n        )\n        file_handler.setFormatter(formatter)\n        logger.addHandler(file_handler)\n    \n    # \u6dfb\u52a0\u4e0a\u4e0b\u6587\u8fc7\u6ee4\u5668\n    context_filter = ContextFilter({\n        'service': 'my-service',\n        'version': '1.0.0'\n    })\n    logger.addFilter(context_filter)\n    \n    return logger\n\n\n# ============ \u65e5\u5fd7\u8bb0\u5f55\u5668\u7c7b ============\nclass StructuredLogger:\n    &quot;&quot;&quot;\u7ed3\u6784\u5316\u65e5\u5fd7\u8bb0\u5f55\u5668&quot;&quot;&quot;\n    \n    def __init__(self, logger: logging.Logger):\n        self._logger = logger\n    \n    def _log(self, level: int, message: str, **kwargs):\n        &quot;&quot;&quot;\u8bb0\u5f55\u7ed3\u6784\u5316\u65e5\u5fd7&quot;&quot;&quot;\n        extra = {'structured_data': kwargs}\n        self._logger.log(level, message, extra=extra)\n    \n    def info(self, message: str, **kwargs):\n        self._log(logging.INFO, message, **kwargs)\n    \n    def error(self, message: str, **kwargs):\n        self._log(logging.ERROR, message, **kwargs)\n    \n    def debug(self, message: str, **kwargs):\n        self._log(logging.DEBUG, message, **kwargs)\n    \n    def warning(self, message: str, **kwargs):\n        self._log(logging.WARNING, message, **kwargs)\n\n\n# ============ \u4e1a\u52a1\u65e5\u5fd7\u8bb0\u5f55 ============\nclass UserService:\n    &quot;&quot;&quot;\u7528\u6237\u670d\u52a1&quot;&quot;&quot;\n    \n    def __init__(self, logger: StructuredLogger):\n        self.logger = logger\n    \n    def create_user(self, username: str, email: str):\n        &quot;&quot;&quot;\u521b\u5efa\u7528\u6237&quot;&quot;&quot;\n        self.logger.info(\n            &quot;\u521b\u5efa\u7528\u6237&quot;,\n            action=&quot;create_user&quot;,\n            username=username,\n            email=email\n        )\n        # \u4e1a\u52a1\u903b\u8f91...\n        return {&quot;id&quot;: 1, &quot;username&quot;: username}\n    \n    def get_user(self, user_id: int):\n        &quot;&quot;&quot;\u83b7\u53d6\u7528\u6237&quot;&quot;&quot;\n        self.logger.info(\n            &quot;\u83b7\u53d6\u7528\u6237&quot;,\n            action=&quot;get_user&quot;,\n            user_id=user_id\n        )\n        # \u4e1a\u52a1\u903b\u8f91...\n        return {&quot;id&quot;: user_id, &quot;username&quot;: &quot;alice&quot;}\n\n\n# ============ ELK\u96c6\u6210\u793a\u4f8b ============\nclass ELKHandler(logging.Handler):\n    &quot;&quot;&quot;ELK\u65e5\u5fd7\u5904\u7406\u5668&quot;&quot;&quot;\n    \n    def __init__(self, host: str, port: int):\n        super().__init__()\n        self.host = host\n        self.port = port\n    \n    def emit(self, record):\n        &quot;&quot;&quot;\u53d1\u9001\u65e5\u5fd7\u5230ELK&quot;&quot;&quot;\n        log_entry = self.format(record)\n        # \u5b9e\u9645\u5b9e\u73b0\u4e2d\u8fd9\u91cc\u4f1a\u53d1\u9001\u5230Logstash\u6216Elasticsearch\n        print(f&quot;[ELK] {log_entry}&quot;)\n\n\ndef main():\n    &quot;&quot;&quot;\u4e3b\u51fd\u6570&quot;&quot;&quot;\n    print(&quot;=&quot;*60)\n    print(&quot;Python\u65e5\u5fd7\u7cfb\u7edf\u67b6\u6784\u8bbe\u8ba1&quot;)\n    print(&quot;=&quot;*60)\n    \n    # \u914d\u7f6e\u65e5\u5fd7\n    logger = setup_logging(\n        level=&quot;INFO&quot;,\n        log_file=&quot;app.log&quot;,\n        json_format=True\n    )\n    \n    structured_logger = StructuredLogger(logger)\n    \n    # \u4f7f\u7528\u65e5\u5fd7\n    print(&quot;\/n\u3010\u7ed3\u6784\u5316\u65e5\u5fd7\u793a\u4f8b\u3011&quot;)\n    user_service = UserService(structured_logger)\n    user_service.create_user(&quot;alice&quot;, &quot;alice@example.com&quot;)\n    user_service.get_user(1)\n    \n    # \u8bb0\u5f55\u5f02\u5e38\n    print(&quot;\/n\u3010\u5f02\u5e38\u65e5\u5fd7\u793a\u4f8b\u3011&quot;)\n    try:\n        1 \/ 0\n    except Exception as e:\n        structured_logger.error(\n            &quot;\u53d1\u751f\u9519\u8bef&quot;,\n            error_type=type(e).__name__,\n            error_message=str(e)\n        )\n    \n    print(&quot;\/n&quot; + &quot;=&quot;*60)\n    print(&quot;\u65e5\u5fd7\u7cfb\u7edf\u603b\u7ed3&quot;)\n    print(&quot;=&quot;*60)\n    print(&quot;1. \u7ed3\u6784\u5316\u65e5\u5fd7: JSON\u683c\u5f0f\u4fbf\u4e8e\u89e3\u6790&quot;)\n    print(&quot;2. \u591a\u5904\u7406\u5668: \u540c\u65f6\u8f93\u51fa\u5230\u63a7\u5236\u53f0\u548c\u6587\u4ef6&quot;)\n    print(&quot;3. \u5f02\u6b65\u5904\u7406: \u907f\u514d\u65e5\u5fd7\u963b\u585e\u4e1a\u52a1&quot;)\n    print(&quot;4. \u4e0a\u4e0b\u6587\u4fe1\u606f: \u6dfb\u52a0\u4e0a\u4e0b\u6587\u4fbf\u4e8e\u8ffd\u8e2a&quot;)\n    print(&quot;5. ELK\u96c6\u6210: \u96c6\u4e2d\u5316\u65e5\u5fd7\u7ba1\u7406&quot;)\n    print(&quot;=&quot;*60)\n\n\nif __name__ == &quot;__main__&quot;:\n    main()<\/code><\/pre>\n<h3>\u65e5\u5fd7\u7cfb\u7edf\u67b6\u6784\u56fe<\/h3>\n<pre style=\"display:none;\"><code class=\"mermaid\">flowchart TB\n    subgraph App[&quot;\u5e94\u7528\u7a0b\u5e8f&quot;]\n        A1[\u4e1a\u52a1\u4ee3\u7801]\n        A2[\u7ed3\u6784\u5316\u65e5\u5fd7]\n    end\n    \n    subgraph Logger[&quot;\u65e5\u5fd7\u7cfb\u7edf&quot;]\n        L1[Logger]\n        L2[Handler]\n        L3[Formatter]\n        L4[Filter]\n    end\n    \n    subgraph Output[&quot;\u8f93\u51fa\u76ee\u6807&quot;]\n        O1[\u63a7\u5236\u53f0]\n        O2[\u6587\u4ef6]\n        O3[ELK Stack]\n    end\n    \n    App --&gt; Logger --&gt; Output<\/code><\/pre>\n<h3>\u5173\u952e\u8981\u70b9<\/h3>\n<ol>\n<li><strong>\u7ed3\u6784\u5316\u65e5\u5fd7<\/strong>\uff1aJSON\u683c\u5f0f\u4fbf\u4e8e\u89e3\u6790\u548c\u5206\u6790<\/li>\n<li><strong>\u591a\u5904\u7406\u5668<\/strong>\uff1a\u540c\u65f6\u8f93\u51fa\u5230\u591a\u4e2a\u76ee\u6807<\/li>\n<li><strong>\u5f02\u6b65\u5904\u7406<\/strong>\uff1a\u907f\u514d\u65e5\u5fd7\u963b\u585e\u4e1a\u52a1\u903b\u8f91<\/li>\n<li><strong>\u4e0a\u4e0b\u6587\u4fe1\u606f<\/strong>\uff1a\u6dfb\u52a0\u4e0a\u4e0b\u6587\u4fbf\u4e8e\u95ee\u9898\u8ffd\u8e2a<\/li>\n<li><strong>ELK\u96c6\u6210<\/strong>\uff1a\u96c6\u4e2d\u5316\u65e5\u5fd7\u7ba1\u7406\u548c\u5206\u6790<\/li>\n<\/ol>\n<p>\u826f\u597d\u7684\u65e5\u5fd7\u7cfb\u7edf\u662f\u7cfb\u7edf\u53ef\u89c2\u6d4b\u6027\u7684\u57fa\u7840\u3002<\/p>\n<p><a href=\"https:\/\/segmentfault.com\/a\/1190000047615719\">https:\/\/segmentfault.com\/a\/1190000047615719<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Python\u65e5\u5fd7\u7cfb\u7edf\u67b6\u6784\u8bbe\u8ba1\u4e0eELK\u96c6\u6210 \u65e5\u5fd7\u662f\u7cfb\u7edf\u53ef\u89c2\u6d4b\u6027\u7684\u91cd\u8981\u7ec4\u6210\u90e8\u5206\u3002\u672c\u6587\u5c06\u4ecb\u7ecdPython\u65e5\u5fd7\u7cfb\u7edf\u67b6\u6784 [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[4],"tags":[],"class_list":["post-10021266","post","type-post","status-publish","format-standard","hentry","category-share"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts\/10021266","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=10021266"}],"version-history":[{"count":0,"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts\/10021266\/revisions"}],"wp:attachment":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=10021266"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=10021266"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=10021266"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}