新版python logging 封装,支持同时向console,file,socket输出

本文介绍了如何优化Python logging模块,实现日志信息同时输出到控制台、文件和远程服务器,并在配置时清空根日志器的处理器,避免重复输出。提供了详细的代码实现及使用方法。

将python的logging封装更新了一下,目前支持同时向console,file,socket输出,同时在config_logging或者config_logging_plus的时候先清除根logger的所有handler,避免在某些情况下的重复输出。
具体代码如下:

# -*- coding: utf-8 -*-
'''
Modified on 2012-11-27
@summary: clear old root logger handlers when reconfig logging
@author: JerryKwan

Created on 2012-06-14 19:50
@summary:  logging config
@author: JerryKwan
'''

import logging

import logging.handlers

import os
import sys

LEVELS = {'NOSET': logging.NOTSET,
          'DEBUG': logging.DEBUG,
          'INFO': logging.INFO,
          'WARNING': logging.WARNING,
          'ERROR': logging.ERROR,
          'CRITICAL': logging.CRITICAL}

#set up logging to file

#logging.basicConfig(level = logging.NOTSET,
#                    format = "%(asctime)s %(name)-12s %(levelname)-8s %(message)s"
#                    )

##                    filename = "./log.txt",

##                    filemode = "w")

# create logs file folder
def config_logging(file_name = "log.txt", log_level = "NOSET"):
    '''
    @summary: config logging to write logs to local file
    @param file_name: name of log file
    @param log_level: log level
    '''
    logs_dir = os.path.join(os.path.dirname(__file__), "logs")
    if os.path.exists(logs_dir) and os.path.isdir(logs_dir):
        pass
    else:
        os.makedirs(logs_dir)

    # clear old root logger handlers
    logging.getLogger("").handlers = []

    file_name = os.path.join(logs_dir, file_name)
    # define a rotating file handler
    rotatingFileHandler = logging.handlers.RotatingFileHandler(filename =file_name,
                                                      maxBytes = 1024 * 1024 * 50,
                                                      backupCount = 5)
    formatter = logging.Formatter("%(asctime)s %(name)-12s %(levelname)-8s %(message)s")
    rotatingFileHandler.setFormatter(formatter)
    logging.getLogger("").addHandler(rotatingFileHandler)

    # define a handler whitch writes messages to sys
    console = logging.StreamHandler()
    # set a format which is simple for console use
    formatter = logging.Formatter("%(name)-12s: %(levelname)-8s %(message)s")
    # tell the handler to use this format
    console.setFormatter(formatter)
    # add the handler to the root logger
    logging.getLogger("").addHandler(console)
    # set initial log level
    logger = logging.getLogger("")
    level = LEVELS[log_level.upper()]
    logger.setLevel(level)

def config_logging_plus(file_name = "log.txt", log_level = "NOSET", remote_address = ("127.0.0.1", 8888), write_console = False):
    '''
    @summary: config logging to write logs to remote service
    @param host: hostname or ip address of the log server
    @param port: port to be used for log server
    @log_level: log level
    '''
    logs_dir = os.path.join(os.path.dirname(__file__), "logs")
    if os.path.exists(logs_dir) and os.path.isdir(logs_dir):
        pass
    else:
        os.makedirs(logs_dir)
    # format file name
    if file_name is None:
        file_name = os.path.splitext(sys.argv[0])[0]
        file_name = os.path.join(logs_dir, "%s_%s.log"%(file_name, os.getpid()))
    else:
        file_name = os.path.join(logs_dir, file_name)

    # clear old root logger handlers
    logging.getLogger("").handlers = []
    
    # define a rotating file handler
    rotatingFileHandler = logging.handlers.RotatingFileHandler(filename =file_name,
                                                      maxBytes = 1024 * 1024 * 50,
                                                      backupCount = 5)
    formatter = logging.Formatter("%(asctime)s %(name)-12s %(levelname)-8s %(message)s")
    rotatingFileHandler.setFormatter(formatter)
    # add log handler
    logging.getLogger("").addHandler(rotatingFileHandler)

    if write_console is not None and  write_console == True:
        # define a handler whitch writes messages to sys
        console = logging.StreamHandler()
        console.setLevel(logging.NOTSET)
        # set a format which is simple for console use
        formatter = logging.Formatter("%(name)-12s: %(levelname)-8s %(message)s")
        # tell the handler to use this format
        console.setFormatter(formatter)
        # add log handler
        logging.getLogger("").addHandler(console)

    if remote_address is not None and hasattr(remote_address, "__iter__") and len(remote_address) > 1:
        # define a socket handler
        socketHandler = logging.handlers.SocketHandler(remote_address[0], remote_address[1])
        formatter = logging.Formatter("%(asctime)s %(processName)s %(process)s %(name)-12s %(levelname)-8s %(message)s")
        socketHandler.setFormatter(formatter)
        # add log handler
        logging.getLogger("").addHandler(socketHandler)

    # set initial log level
    logger = logging.getLogger("")
    level = LEVELS[log_level.upper()]
    logger.setLevel(level)

使用方法很简单,只需要需要config logging的时候config一下即可,示例代码如下:

import loggingconfig
loggingconfig.config_logging(file_name = "log.log", log_level = "NOSET")

转载于:https://www.cnblogs.com/Jerryshome/archive/2012/11/27/2791416.html

要将封装的日志类支持将日志发送到远程服务器(如 ELK、Graylog),你需要扩展日志输出目标。Loguru 本身不直接支持远程日志发送,但你可以通过自定义 `sink`(日志接收器)来实现。 --- ## ✅ 实现方式概述 Loguru 支持使用自定义函数作为日志的 `sink`,你可以编写一个将日志发送到远程服务器的函数,并将其作为 sink 添加到 logger 中。 ### ✅ 支持的日志服务器类型 - **ELK Stack(Elasticsearch + Logstash + Kibana)** - **Graylog** - **Fluentd** - **HTTP 日志服务(如自建 API)** - **Syslog 服务器** --- ## ✅ 示例:封装支持远程日志发送的 `Logger` 类 下面是一个封装了本地文件、控制台输出,并支持发送日志到远程服务器(如 ELK、Graylog)的完整示例。 ### ✅ 1. 安装依赖(如使用 HTTP 发送) ```bash pip install loguru requests ``` --- ### ✅ 2. 封装日志类(支持远程日志) ```python # utils/logger.py from loguru import logger import os import requests import logging import socket from functools import partial # 日志配置 LOG_CONFIG = { "log_file": "logs/app.log", "level": "DEBUG", "rotation": "10 MB", "retention": "7 days", "console_format": "<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>", "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level} | {name}:{function}:{line} - {message}", "remote_url": "http://your-logging-server.com/api/logs", # 替换为你的远程日志服务地址 "enable_remote": True, "hostname": socket.gethostname(), } class AppLogger: _instance = None def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance = super(AppLogger, cls).__new__(cls) cls._instance._initialize(*args, **kwargs) return cls._instance def _initialize(self): log_dir = os.path.dirname(LOG_CONFIG["log_file"]) os.makedirs(log_dir, exist_ok=True) # 清除默认日志输出 logger.remove() # 控制台输出 logger.add( lambda msg: print(msg, end=''), level=LOG_CONFIG["level"], colorize=True, format=LOG_CONFIG["console_format"], ) # 文件输出 logger.add( LOG_CONFIG["log_file"], rotation=LOG_CONFIG["rotation"], retention=LOG_CONFIG["retention"], level=LOG_CONFIG["level"], format=LOG_CONFIG["file_format"], ) # 远程日志输出(HTTP) if LOG_CONFIG["enable_remote"]: logger.add( self._remote_sink, level=LOG_CONFIG["level"], format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {name}:{function}:{line} - {message}" ) self._logger = logger def _remote_sink(self, message): """将日志发送到远程 HTTP 日志服务器""" try: log_data = { "message": message, "host": LOG_CONFIG["hostname"], "level": message.record["level"].name, "timestamp": message.record["time"].isoformat(), } requests.post(LOG_CONFIG["remote_url"], json=log_data, timeout=5) except Exception as e: print(f"Failed to send log to remote server: {e}") def get_logger(self): return self._logger # 实例化一个全局日志对象 log = AppLogger().get_logger() ``` --- ## ✅ 3. 使用封装的日志类 ```python # main.py from utils.logger import log if __name__ == "__main__": log.info("这是一条测试日志,将被发送到远程服务器") ``` --- ## ✅ 4. 配置远程日志服务器 ### ✅ 4.1 Graylog 示例(GELF) Graylog 支持 GELF 协议,你可以使用 `graypy` 库发送日志: ```bash pip install graypy ``` ```python import graypy gelf_handler = graypy.GELFUDPHandler("graylog.example.com", 12201) logger.add(gelf_handler, level="INFO", serialize=True) ``` ### ✅ 4.2 ELK Stack(通过 Logstash) 你可以将日志发送到 Logstash 的 TCP/UDP 或 HTTP 输入端口,Logstash 再转发到 Elasticsearch。 --- ## ✅ 5. 进阶:支持 Syslog、TCP、UDP 等协议 你可以使用 Python 的 `logging.handlers` 模块与 Loguru 的 `sink` 结合使用: ```python import logging import logging.handlers class SyslogHandler(logging.Handler): def __init__(self, host='localhost', port=514): super().__init__() self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.host = host self.port = port def emit(self, record): msg = self.format(record) self.sock.sendto(msg.encode(), (self.host, self.port)) syslog_handler = SyslogHandler('syslog.example.com', 514) logger.add(syslog_handler, format="{message}", level="INFO") ``` --- ## ✅ 总结 | 功能 | 实现方式 | |------|----------| | 本地日志输出 | 使用 `logger.add(file)` | | 控制台输出 | 使用 `logger.add(lambda msg: print(...))` | | 远程 HTTP 日志 | 自定义 `sink` 发送 HTTP 请求 | | Graylog/GELF | 使用 `graypy` | | Syslog/TCP/UDP | 使用 `socket` 或 `logging.handlers` | | 单例模式 | 使用 `_instance` 控制实例化 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值