zoukankan      html  css  js  c++  java
  • django的日志发往http server

    配置示例:

    # https://docs.djangoproject.com/zh-hans/2.1/topics/logging/
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {  # 格式器
            'verbose': {
                # 后缀d表示数据格式是整数,s表示数据格式是字符串
                'format': '[%(levelname)s] [%(asctime)s] [%(module)s] %(filename)s:%(lineno)d %(funcName)s '
                          '%(processName)s:[%(process)d] %(threadName)s:[%(thread)d] %(message)s'
                # 'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
                # 'style': '{',
            },
            'simple': {
                'format': '[%(levelname)s] [%(asctime)s] %(message)s',
                # 'format': '[%(asctime)s] %(message)s',
                # 后缀d表示数据格式是整数,s表示数据格式是字符串
                # 'format': '[%(levelname)s] [%(asctime)s] [%(module)s] %(filename)s:%(lineno)d %(funcName)s '
                #           '%(processName)s:[%(process)d] %(threadName)s:[%(thread)d] %(message)s',
                # 'style': '{',
            },
            'standard': {
                # 'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s',
                'format': '{asctime} [{levelname:6}] {name:30}: {message}',
                # 设置上面格式样式;{lineno:3}是行号,至少显示3个字符,少则补空格
                # 这里style选择{,是指{asctime}这种形式。
                # 如果选择%,则是%(asctime)s这种形式。
                # 还有一种选择,是$,是$asctime或${asctime}这种形式。
                'style': '{',
                # 设置时间格式
                'datefmt': '%Y-%m-%d %H:%M:%S',
            },
            'operation': {
                'format': '%(message)s'
            }
        },
        # 'filters': {
        #     # 'special': {
        #     #     '()': 'erebus.logging.SpecialFilter',
        #     #     'foo': 'bar',
        #     # },
        #     'require_debug_true': {
        #         '()': 'django.utils.log.RequireDebugTrue',
        #     },
        # },
    
        # Handler是决定如何处理logger中每一条消息的引擎。它描述特定的日志行为,比如把消息输出到屏幕、文件或网络socket。
        # 和 logger 一样,handler 也有日志级别的概念。如果一条日志记录的级别不匹配或者低于 handler 的日志级别,
        # 对应的消息会被 handler 忽略。
        'handlers': {   # 处理器
            'default': {
                'level': 'DEBUG',
                'class': 'logging.handlers.RotatingFileHandler',
                'filename': 'logs/default.log',
                'maxBytes': 1024*1024*5*20,  # 5*20 MB
                # 'maxBytes': 1024*5,  # 5 KB
                # 保留7天的日志,没份5M,5份大概是一个小时的日志内容,主要是kafka日志
                'backupCount': int(5*1*24*7/20),
                'formatter': 'standard',
            },
            'kafka': {
                'level': 'DEBUG',
                'class': 'logging.handlers.RotatingFileHandler',
                'filename': 'logs/kafka.log',
                'maxBytes': 1024*1024*5*20,  # 5*20 MB
                # 'maxBytes': 1024*5,  # 5 KB
                # 保留7天的日志,没份5M,5份大概是一个小时的日志内容,主要是kafka日志
                'backupCount': int(5*1*24*7/20),
                'formatter': 'standard',
            },
            'output_to_server': {   # 输出到http server,参数来自类HTTPHandler初始化函数里的参数
                'level': 'WARNING',  # 忽略debug/info信息
                'class': 'logging.handlers.HTTPHandler',
                'host': '127.0.0.1:8088',
                'url': '/api/v1/log',
                # 使用GET方法遇到url最大长度限制
                'method': 'POST',
                'formatter': 'verbose',
            },
            'django': {
                'level': 'INFO',  # 忽略debug信息
                'class': 'logging.FileHandler',
                'filename': '{}/{}.log'.format(BASE_LOG_DIR, conf.get('log', 'name')),
                'formatter': 'simple' if DEBUG else 'verbose',
                'encoding': 'utf8',
            },
            'console': {
                'level': 'DEBUG',  # 所有的日志都会被输出到console
                # 'filters': ['require_debug_true'],
                'class': 'logging.StreamHandler',
                'formatter': 'simple'
            },
            'operation': {
                'level': 'INFO',
                'class': 'logging.FileHandler',
                'filename': '{}/{}.log'.format(BASE_LOG_DIR, 'operation'),
                'formatter': 'operation',
                'encoding': 'utf8'
            },
            'test': {
                'level': 'INFO',
                'class': 'logging.FileHandler',
                'filename': '{}/{}.log'.format(BASE_LOG_DIR, 'test'),
                'formatter': 'standard',
                'encoding': 'utf8'
            }
            # 'mail_admins': {
            #     'level': 'ERROR',
            #     'class': 'django.utils.log.AdminEmailHandler',
            #     # 'filters': ['special']
            # }
        },
        'loggers': {   # 记录器
    
            # 可以通过使用空字符串:''来设置'catch all' logger
            # 在以下设置中,将所有日志事件级别为WARNING及以上的日志发送给日志服务器,但配置为'propagate': False日志事件除外,
            '': {
                'handlers': ['default', 'output_to_server'],
                # 这样情况下的level设置是无效的,所有级别的信息都会传给handlers处理,由handlers的level界别决定
                'level': 'ERROR',
                'propagate': False
            },
            # 记录所有kakfa相关的日志
            'kafka': {
                'handlers': ['kafka'],
                'level': 'DEBUG',
                'propagate': True
            },
            # 这里必须使用名字django和django.request,目的是为了捕获django框架的日志内容
            'django': {
                'handlers': ['django', 'console'],
                # 当 logger 处理一条消息时,会将自己的日志级别和这条消息的日志级别做对比。
                # 如果消息的日志级别匹配或者高于 logger 的日志级别,它就会被进一步处理。
                # 否则这条消息就会被忽略掉。当 logger 确定了一条消息需要处理之后,会把它传给 Handler。
                # 把INFO及以上级别的日志传给handlers,然后由handlers根据handlers的level进一步处理日志输出
                'level': 'INFO',
                'propagate': True,  # 若值为False,表示日志不会传到上个层级,自然也不会传到default.log里
            },
            # 使用logger = logging.getLogger('django.request'), logger.info('info'),
            # 可以把日志输出到'handlers': ['django', 'console'],
            'django.request': {
                # 即使和django的handlers一样,level也一样,也并不会产生2次相同的日志内容,应该是个并集。
                'handlers': ['django', 'console'],
                'level': 'DEBUG',
                # 会把日志向django.request的上层django传播
                'propagate': True,
            },
            # sql语句
            'django.db.backends': {
                # 即使和django的handlers一样,level也一样,也并不会产生2次相同的日志内容,应该是个并集。
                'handlers': ['django', 'console'],
                'level': 'DEBUG',
                # 会把日志向django.request的上层django传播
                'propagate': True,
            },
            # 'erebus.custom': {
            #     'handlers': ['console', 'mail_admins'],
            #     'level': 'INFO',
            #     # 'filters': ['special']
            # },
            # 名字随意起,用时,使用logger = logging.getLogger(conf.get('log', 'name'))获取,传到相应的loggers里就可以
            'operation': {
                'handlers': ['operation'],
                'level': 'INFO',
                'propagate': True,
            },
            'test': {
                'handlers': ['console', 'test'],
                'level': 'INFO',
                'propagate': False,  # 不要传给上一层级
            }
        }
    }

    查看使用的class HTTPHandler,注意参数对应

    class HTTPHandler(logging.Handler):
        """
        A class which sends records to a Web server, using either GET or
        POST semantics.
        """
        def __init__(self, host, url, method="GET", secure=False, credentials=None,
                     context=None):
            """
            Initialize the instance with the host, the request URL, and the method
            ("GET" or "POST")
            """
            logging.Handler.__init__(self)
            method = method.upper()
            if method not in ["GET", "POST"]:
                raise ValueError("method must be GET or POST")
            if not secure and context is not None:
                raise ValueError("context parameter only makes sense "
                                 "with secure=True")
            self.host = host
            self.url = url
            self.method = method
            self.secure = secure
            self.credentials = credentials
            self.context = context
    
        def mapLogRecord(self, record):
            """
            Default implementation of mapping the log record into a dict
            that is sent as the CGI data. Overwrite in your class.
            Contributed by Franz Glasner.
            """
            return record.__dict__
    
        def emit(self, record):
            """
            Emit a record.
    
            Send the record to the Web server as a percent-encoded dictionary
            """
            try:
                import http.client, urllib.parse
                host = self.host
                if self.secure:
                    h = http.client.HTTPSConnection(host, context=self.context)
                else:
                    h = http.client.HTTPConnection(host)
                url = self.url
                data = urllib.parse.urlencode(self.mapLogRecord(record))
                if self.method == "GET":
                    if (url.find('?') >= 0):
                        sep = '&'
                    else:
                        sep = '?'
                    url = url + "%c%s" % (sep, data)
                h.putrequest(self.method, url)
                # support multiple hosts on one IP address...
                # need to strip optional :port from host, if present
                i = host.find(":")
                if i >= 0:
                    host = host[:i]
                # See issue #30904: putrequest call above already adds this header
                # on Python 3.x.
                # h.putheader("Host", host)
                if self.method == "POST":
                    h.putheader("Content-type",
                                "application/x-www-form-urlencoded")
                    h.putheader("Content-length", str(len(data)))
                if self.credentials:
                    import base64
                    s = ('%s:%s' % self.credentials).encode('utf-8')
                    s = 'Basic ' + base64.b64encode(s).strip().decode('ascii')
                    h.putheader('Authorization', s)
                h.endheaders()
                if self.method == "POST":
                    h.send(data.encode('utf-8'))
                h.getresponse()    #can't do anything with the result
            except Exception:
                self.handleError(record)

    参考:https://cloud.tencent.com/developer/ask/183866

  • 相关阅读:
    【LeetCode】Rotate List
    【LeetCode】Longest Valid Parentheses
    【LeetCode】Longest Substring Without Repeating Characters
    【LeetCode】Multiply Strings
    【LeetCode】Triangle
    hdfs 查看报告--命令(hdfs dfsadmin -report)
    hive
    java ---面向对象
    java--数组
    java--函数
  • 原文地址:https://www.cnblogs.com/shengulong/p/10473260.html
Copyright © 2011-2022 走看看