# -*- coding: utf-8 -*-
import logging
import sys
import inspect
# from functools import lru_cache
from datetime import datetime
class OptimizedFormatter( logging .Formatter ) :
def __init__ ( self , *args, **kwargs) :
super ( OptimizedFormatter, self ) .__init__ ( *args, **kwargs)
self ._frame_blacklist = { id ( inspect .currentframe ( ) ) }
def format( self , record) :
try :
# 智能帧信息捕获
if not all ( hasattr ( record, attr) for attr in [ 'module' , 'lineno' , 'funcName' ] ) :
frame = self ._find_caller_frame( )
if frame:
self ._populate_record( record, frame)
# 统一参数处理
args_str = self ._process_arguments( record)
if args_str:
record.message = u"%s ⎸ %s" % ( record.message , args_str)
else :
record.message = record.getMessage ( )
return super ( OptimizedFormatter, self ) .format ( record)
except Exception as e:
return u"⚠️ Format Error | Err: %s | Raw: %s" % ( e, record.getMessage ( ) )
# @lru_cache(maxsize=128)
def _find_caller_frame( self ) :
"""带缓存的调用帧查找"""
stack = inspect .stack ( )
for frame_info in reversed ( stack) :
frame = frame_info[ 0 ]
if id ( frame) not in self ._frame_blacklist and \
inspect .getmodule ( frame) .__name__ != __name__:
return frame
return inspect .currentframe ( )
def _populate_record( self , record, frame) :
"""填充记录元数据"""
module = inspect .getmodule ( frame)
record.module = module.__name__ if module else 'unknown'
record.lineno = frame.f_lineno
record.funcName = frame.f_code .co_name
def _process_arguments( self , record) :
"""统一参数处理"""
parts = [ ]
# 处理位置参数
if hasattr ( record, 'positional_args' ) and record.positional_args :
parts.extend ( self ._safe_repr( a) for a in record.positional_args )
# 处理关键字参数
if hasattr ( record, 'extra_kwargs' ) and record.extra_kwargs :
parts.extend ( u"%s=%s" % ( k, self ._safe_repr( v) )
for k, v in record.extra_kwargs .items ( ) )
return u" ⎸ " .join ( parts) if parts else u""
def _safe_repr( self , value) :
"""安全类型表示"""
try :
if isinstance ( value, dict ) :
return u"{%s}" % u"," .join ( u"%s:%s" % ( self ._safe_repr( k) , self ._safe_repr( v) )
for k, v in value.items ( ) )
if isinstance ( value, ( list , tuple ) ) :
seq_type = u"[]" if isinstance ( value, list ) else u"()"
return u"%s%s%s" % ( seq_type[ 0 ] , u"," .join ( self ._safe_repr( x) for x in value) , seq_type[ 1 ] )
return self ._safe_str( value)
except :
return u"<Unrepresentable>"
@ staticmethod
def _safe_str( obj) :
"""安全字符串转换"""
try :
if isinstance ( obj, bytes ) :
return obj.decode ( 'utf-8' , 'replace' )
return str ( obj)
except UnicodeDecodeError :
return u"<Non-UTF8 Binary Data>"
except :
return u"<Unconvertible Object>"
class SimpleLogger( object ) :
_initialized = False
@ classmethod
def _ensure_init( cls) :
if not cls._initialized:
root = logging .getLogger ( )
root.setLevel ( logging .DEBUG )
if not root.handlers :
handler = logging .StreamHandler ( )
handler.setFormatter ( OptimizedFormatter(
fmt= u'[%(asctime)s] [%(levelname)s] %(module)s:%(lineno)d ➤ [%(funcName)s] %(message)s' ,
datefmt= '%H:%M:%S'
) )
root.addHandler ( handler)
cls._initialized = True
@ classmethod
def _log( cls, level, msg, *args, **kwargs) :
cls._ensure_init( )
try :
# 消息预处理
msg = cls._preprocess_message( msg)
# 获取调用上下文
frame = inspect .currentframe ( ) .f_back .f_back
logger = logging .getLogger (
inspect .getmodule ( frame) .__name__
if inspect .getmodule ( frame) else 'unknown'
)
# 创建日志记录
logger.log (
level,
msg,
extra= {
'positional_args' : args,
'extra_kwargs' : kwargs
} ,
# stacklevel=3 # Python 3.8+ 支持
)
except Exception as e:
sys .stderr .write ( u"Log Error: %s\n " % str ( e) )
@ staticmethod
def _preprocess_message( msg) :
"""消息预处理"""
if isinstance ( msg, bytes ) :
try :
return msg.decode ( 'utf-8' )
except UnicodeDecodeError :
return msg.decode ( 'latin-1' , 'replace' )
return str ( msg)
@ classmethod
def debug( cls, msg, *args, **kwargs) :
cls._log( logging .DEBUG , msg, *args, **kwargs)
@ classmethod
def info( cls, msg, *args, **kwargs) :
cls._log( logging .INFO , msg, *args, **kwargs)
@ classmethod
def warning( cls, msg, *args, **kwargs) :
cls._log( logging .WARNING , msg, *args, **kwargs)
@ classmethod
def error( cls, msg, *args, **kwargs) :
cls._log( logging .ERROR , msg, *args, **kwargs)
# 测试用例
if __name__ == "__main__" :
# 测试中文日志
SimpleLogger.info ( u"用户登录" , u"张三" , ip= "192.168.1.100" )
# 测试混合参数
SimpleLogger.error ( "配置错误" , "database" , code = 500 , detail= { "line" : 42 , "file" : "app.conf" } )
# 测试二进制数据
bad_data = b'\x e6\x 97\x a0' # UTF-8编码的"无"
SimpleLogger.warning ( "无效数据流" , bad_data, sector= [ 0x12 , 0xff , 0x7f ] )
# 测试嵌套参数
SimpleLogger.debug ( "调试信息" , { "key" : [ 1 , 2 , 3 ] } , timeout= 30.5 )
IyAtKi0gY29kaW5nOiB1dGYtOCAtKi0KaW1wb3J0IGxvZ2dpbmcKaW1wb3J0IHN5cwppbXBvcnQgaW5zcGVjdAojIGZyb20gZnVuY3Rvb2xzIGltcG9ydCBscnVfY2FjaGUKZnJvbSBkYXRldGltZSBpbXBvcnQgZGF0ZXRpbWUKCgpjbGFzcyBPcHRpbWl6ZWRGb3JtYXR0ZXIobG9nZ2luZy5Gb3JtYXR0ZXIpOgogICAgZGVmIF9faW5pdF9fKHNlbGYsICphcmdzLCAqKmt3YXJncyk6CiAgICAgICAgc3VwZXIoT3B0aW1pemVkRm9ybWF0dGVyLCBzZWxmKS5fX2luaXRfXygqYXJncywgKiprd2FyZ3MpCiAgICAgICAgc2VsZi5fZnJhbWVfYmxhY2tsaXN0ID0ge2lkKGluc3BlY3QuY3VycmVudGZyYW1lKCkpfQoKICAgIGRlZiBmb3JtYXQoc2VsZiwgcmVjb3JkKToKICAgICAgICB0cnk6CiAgICAgICAgICAgICMg5pm66IO95bin5L+h5oGv5o2V6I63CiAgICAgICAgICAgIGlmIG5vdCBhbGwoaGFzYXR0cihyZWNvcmQsIGF0dHIpIGZvciBhdHRyIGluIFsnbW9kdWxlJywgJ2xpbmVubycsICdmdW5jTmFtZSddKToKICAgICAgICAgICAgICAgIGZyYW1lID0gc2VsZi5fZmluZF9jYWxsZXJfZnJhbWUoKQogICAgICAgICAgICAgICAgaWYgZnJhbWU6CiAgICAgICAgICAgICAgICAgICAgc2VsZi5fcG9wdWxhdGVfcmVjb3JkKHJlY29yZCwgZnJhbWUpCgogICAgICAgICAgICAjIOe7n+S4gOWPguaVsOWkhOeQhgogICAgICAgICAgICBhcmdzX3N0ciA9IHNlbGYuX3Byb2Nlc3NfYXJndW1lbnRzKHJlY29yZCkKICAgICAgICAgICAgaWYgYXJnc19zdHI6CiAgICAgICAgICAgICAgICByZWNvcmQubWVzc2FnZSA9IHUiJXMg4o64ICVzIiAlIChyZWNvcmQubWVzc2FnZSwgYXJnc19zdHIpCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICByZWNvcmQubWVzc2FnZSA9IHJlY29yZC5nZXRNZXNzYWdlKCkKCiAgICAgICAgICAgIHJldHVybiBzdXBlcihPcHRpbWl6ZWRGb3JtYXR0ZXIsIHNlbGYpLmZvcm1hdChyZWNvcmQpCiAgICAgICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlOgogICAgICAgICAgICByZXR1cm4gdSLimqDvuI8gRm9ybWF0IEVycm9yIHwgRXJyOiAlcyB8IFJhdzogJXMiICUgKGUsIHJlY29yZC5nZXRNZXNzYWdlKCkpCgogICAgIyBAbHJ1X2NhY2hlKG1heHNpemU9MTI4KQogICAgZGVmIF9maW5kX2NhbGxlcl9mcmFtZShzZWxmKToKICAgICAgICAiIiLluKbnvJPlrZjnmoTosIPnlKjluKfmn6Xmib4iIiIKICAgICAgICBzdGFjayA9IGluc3BlY3Quc3RhY2soKQogICAgICAgIGZvciBmcmFtZV9pbmZvIGluIHJldmVyc2VkKHN0YWNrKToKICAgICAgICAgICAgZnJhbWUgPSBmcmFtZV9pbmZvWzBdCiAgICAgICAgICAgIGlmIGlkKGZyYW1lKSBub3QgaW4gc2VsZi5fZnJhbWVfYmxhY2tsaXN0IGFuZCBcCiAgICAgICAgICAgICAgIGluc3BlY3QuZ2V0bW9kdWxlKGZyYW1lKS5fX25hbWVfXyAhPSBfX25hbWVfXzoKICAgICAgICAgICAgICAgIHJldHVybiBmcmFtZQogICAgICAgIHJldHVybiBpbnNwZWN0LmN1cnJlbnRmcmFtZSgpCgogICAgZGVmIF9wb3B1bGF0ZV9yZWNvcmQoc2VsZiwgcmVjb3JkLCBmcmFtZSk6CiAgICAgICAgIiIi5aGr5YWF6K6w5b2V5YWD5pWw5o2uIiIiCiAgICAgICAgbW9kdWxlID0gaW5zcGVjdC5nZXRtb2R1bGUoZnJhbWUpCiAgICAgICAgcmVjb3JkLm1vZHVsZSA9IG1vZHVsZS5fX25hbWVfXyBpZiBtb2R1bGUgZWxzZSAndW5rbm93bicKICAgICAgICByZWNvcmQubGluZW5vID0gZnJhbWUuZl9saW5lbm8KICAgICAgICByZWNvcmQuZnVuY05hbWUgPSBmcmFtZS5mX2NvZGUuY29fbmFtZQoKICAgIGRlZiBfcHJvY2Vzc19hcmd1bWVudHMoc2VsZiwgcmVjb3JkKToKICAgICAgICAiIiLnu5/kuIDlj4LmlbDlpITnkIYiIiIKICAgICAgICBwYXJ0cyA9IFtdCiAgICAgICAgCiAgICAgICAgIyDlpITnkIbkvY3nva7lj4LmlbAKICAgICAgICBpZiBoYXNhdHRyKHJlY29yZCwgJ3Bvc2l0aW9uYWxfYXJncycpIGFuZCByZWNvcmQucG9zaXRpb25hbF9hcmdzOgogICAgICAgICAgICBwYXJ0cy5leHRlbmQoc2VsZi5fc2FmZV9yZXByKGEpIGZvciBhIGluIHJlY29yZC5wb3NpdGlvbmFsX2FyZ3MpCiAgICAgICAgCiAgICAgICAgIyDlpITnkIblhbPplK7lrZflj4LmlbAKICAgICAgICBpZiBoYXNhdHRyKHJlY29yZCwgJ2V4dHJhX2t3YXJncycpIGFuZCByZWNvcmQuZXh0cmFfa3dhcmdzOgogICAgICAgICAgICBwYXJ0cy5leHRlbmQodSIlcz0lcyIgJSAoaywgc2VsZi5fc2FmZV9yZXByKHYpKSAKICAgICAgICAgICAgICAgICAgICAgICBmb3IgaywgdiBpbiByZWNvcmQuZXh0cmFfa3dhcmdzLml0ZW1zKCkpCiAgICAgICAgCiAgICAgICAgcmV0dXJuIHUiIOKOuCAiLmpvaW4ocGFydHMpIGlmIHBhcnRzIGVsc2UgdSIiCgogICAgZGVmIF9zYWZlX3JlcHIoc2VsZiwgdmFsdWUpOgogICAgICAgICIiIuWuieWFqOexu+Wei+ihqOekuiIiIgogICAgICAgIHRyeToKICAgICAgICAgICAgaWYgaXNpbnN0YW5jZSh2YWx1ZSwgZGljdCk6CiAgICAgICAgICAgICAgICByZXR1cm4gdSJ7JXN9IiAlIHUiLCIuam9pbih1IiVzOiVzIiAlIChzZWxmLl9zYWZlX3JlcHIoayksIHNlbGYuX3NhZmVfcmVwcih2KSkgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIGssIHYgaW4gdmFsdWUuaXRlbXMoKSkKICAgICAgICAgICAgaWYgaXNpbnN0YW5jZSh2YWx1ZSwgKGxpc3QsIHR1cGxlKSk6CiAgICAgICAgICAgICAgICBzZXFfdHlwZSA9IHUiW10iIGlmIGlzaW5zdGFuY2UodmFsdWUsIGxpc3QpIGVsc2UgdSIoKSIKICAgICAgICAgICAgICAgIHJldHVybiB1IiVzJXMlcyIgJSAoc2VxX3R5cGVbMF0sIHUiLCIuam9pbihzZWxmLl9zYWZlX3JlcHIoeCkgZm9yIHggaW4gdmFsdWUpLCBzZXFfdHlwZVsxXSkKICAgICAgICAgICAgcmV0dXJuIHNlbGYuX3NhZmVfc3RyKHZhbHVlKQogICAgICAgIGV4Y2VwdDoKICAgICAgICAgICAgcmV0dXJuIHUiPFVucmVwcmVzZW50YWJsZT4iCgogICAgQHN0YXRpY21ldGhvZAogICAgZGVmIF9zYWZlX3N0cihvYmopOgogICAgICAgICIiIuWuieWFqOWtl+espuS4sui9rOaNoiIiIgogICAgICAgIHRyeToKICAgICAgICAgICAgaWYgaXNpbnN0YW5jZShvYmosIGJ5dGVzKToKICAgICAgICAgICAgICAgIHJldHVybiBvYmouZGVjb2RlKCd1dGYtOCcsICdyZXBsYWNlJykKICAgICAgICAgICAgcmV0dXJuIHN0cihvYmopCiAgICAgICAgZXhjZXB0IFVuaWNvZGVEZWNvZGVFcnJvcjoKICAgICAgICAgICAgcmV0dXJuIHUiPE5vbi1VVEY4IEJpbmFyeSBEYXRhPiIKICAgICAgICBleGNlcHQ6CiAgICAgICAgICAgIHJldHVybiB1IjxVbmNvbnZlcnRpYmxlIE9iamVjdD4iCgoKY2xhc3MgU2ltcGxlTG9nZ2VyKG9iamVjdCk6CiAgICBfaW5pdGlhbGl6ZWQgPSBGYWxzZQoKICAgIEBjbGFzc21ldGhvZAogICAgZGVmIF9lbnN1cmVfaW5pdChjbHMpOgogICAgICAgIGlmIG5vdCBjbHMuX2luaXRpYWxpemVkOgogICAgICAgICAgICByb290ID0gbG9nZ2luZy5nZXRMb2dnZXIoKQogICAgICAgICAgICByb290LnNldExldmVsKGxvZ2dpbmcuREVCVUcpCiAgICAgICAgICAgIGlmIG5vdCByb290LmhhbmRsZXJzOgogICAgICAgICAgICAgICAgaGFuZGxlciA9IGxvZ2dpbmcuU3RyZWFtSGFuZGxlcigpCiAgICAgICAgICAgICAgICBoYW5kbGVyLnNldEZvcm1hdHRlcihPcHRpbWl6ZWRGb3JtYXR0ZXIoCiAgICAgICAgICAgICAgICAgICAgZm10PXUnWyUoYXNjdGltZSlzXSBbJShsZXZlbG5hbWUpc10gJShtb2R1bGUpczolKGxpbmVubylkIOKepCBbJShmdW5jTmFtZSlzXSAlKG1lc3NhZ2UpcycsCiAgICAgICAgICAgICAgICAgICAgZGF0ZWZtdD0nJUg6JU06JVMnCiAgICAgICAgICAgICAgICApKQogICAgICAgICAgICAgICAgcm9vdC5hZGRIYW5kbGVyKGhhbmRsZXIpCiAgICAgICAgICAgIGNscy5faW5pdGlhbGl6ZWQgPSBUcnVlCgogICAgQGNsYXNzbWV0aG9kCiAgICBkZWYgX2xvZyhjbHMsIGxldmVsLCBtc2csICphcmdzLCAqKmt3YXJncyk6CiAgICAgICAgY2xzLl9lbnN1cmVfaW5pdCgpCiAgICAgICAgdHJ5OgogICAgICAgICAgICAjIOa2iOaBr+mihOWkhOeQhgogICAgICAgICAgICBtc2cgPSBjbHMuX3ByZXByb2Nlc3NfbWVzc2FnZShtc2cpCiAgICAgICAgICAgIAogICAgICAgICAgICAjIOiOt+WPluiwg+eUqOS4iuS4i+aWhwogICAgICAgICAgICBmcmFtZSA9IGluc3BlY3QuY3VycmVudGZyYW1lKCkuZl9iYWNrLmZfYmFjawogICAgICAgICAgICBsb2dnZXIgPSBsb2dnaW5nLmdldExvZ2dlcigKICAgICAgICAgICAgICAgIGluc3BlY3QuZ2V0bW9kdWxlKGZyYW1lKS5fX25hbWVfXyAKICAgICAgICAgICAgICAgIGlmIGluc3BlY3QuZ2V0bW9kdWxlKGZyYW1lKSBlbHNlICd1bmtub3duJwogICAgICAgICAgICApCgogICAgICAgICAgICAjIOWIm+W7uuaXpeW/l+iusOW9lQogICAgICAgICAgICBsb2dnZXIubG9nKAogICAgICAgICAgICAgICAgbGV2ZWwsCiAgICAgICAgICAgICAgICBtc2csCiAgICAgICAgICAgICAgICBleHRyYT17CiAgICAgICAgICAgICAgICAgICAgJ3Bvc2l0aW9uYWxfYXJncyc6IGFyZ3MsCiAgICAgICAgICAgICAgICAgICAgJ2V4dHJhX2t3YXJncyc6IGt3YXJncwogICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgICMgc3RhY2tsZXZlbD0zICAjIFB5dGhvbiAzLjgrIOaUr+aMgQogICAgICAgICAgICApCiAgICAgICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlOgogICAgICAgICAgICBzeXMuc3RkZXJyLndyaXRlKHUiTG9nIEVycm9yOiAlc1xuIiAlIHN0cihlKSkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgX3ByZXByb2Nlc3NfbWVzc2FnZShtc2cpOgogICAgICAgICIiIua2iOaBr+mihOWkhOeQhiIiIgogICAgICAgIGlmIGlzaW5zdGFuY2UobXNnLCBieXRlcyk6CiAgICAgICAgICAgIHRyeToKICAgICAgICAgICAgICAgIHJldHVybiBtc2cuZGVjb2RlKCd1dGYtOCcpCiAgICAgICAgICAgIGV4Y2VwdCBVbmljb2RlRGVjb2RlRXJyb3I6CiAgICAgICAgICAgICAgICByZXR1cm4gbXNnLmRlY29kZSgnbGF0aW4tMScsICdyZXBsYWNlJykKICAgICAgICByZXR1cm4gc3RyKG1zZykKCiAgICBAY2xhc3NtZXRob2QKICAgIGRlZiBkZWJ1ZyhjbHMsIG1zZywgKmFyZ3MsICoqa3dhcmdzKToKICAgICAgICBjbHMuX2xvZyhsb2dnaW5nLkRFQlVHLCBtc2csICphcmdzLCAqKmt3YXJncykKCiAgICBAY2xhc3NtZXRob2QKICAgIGRlZiBpbmZvKGNscywgbXNnLCAqYXJncywgKiprd2FyZ3MpOgogICAgICAgIGNscy5fbG9nKGxvZ2dpbmcuSU5GTywgbXNnLCAqYXJncywgKiprd2FyZ3MpCgogICAgQGNsYXNzbWV0aG9kCiAgICBkZWYgd2FybmluZyhjbHMsIG1zZywgKmFyZ3MsICoqa3dhcmdzKToKICAgICAgICBjbHMuX2xvZyhsb2dnaW5nLldBUk5JTkcsIG1zZywgKmFyZ3MsICoqa3dhcmdzKQoKICAgIEBjbGFzc21ldGhvZAogICAgZGVmIGVycm9yKGNscywgbXNnLCAqYXJncywgKiprd2FyZ3MpOgogICAgICAgIGNscy5fbG9nKGxvZ2dpbmcuRVJST1IsIG1zZywgKmFyZ3MsICoqa3dhcmdzKQoKCiMg5rWL6K+V55So5L6LCmlmIF9fbmFtZV9fID09ICJfX21haW5fXyI6CiAgICAjIOa1i+ivleS4reaWh+aXpeW/lwogICAgU2ltcGxlTG9nZ2VyLmluZm8odSLnlKjmiLfnmbvlvZUiLCB1IuW8oOS4iSIsIGlwPSIxOTIuMTY4LjEuMTAwIikKICAgIAogICAgIyDmtYvor5Xmt7flkIjlj4LmlbAKICAgIFNpbXBsZUxvZ2dlci5lcnJvcigi6YWN572u6ZSZ6K+vIiwgImRhdGFiYXNlIiwgY29kZT01MDAsIGRldGFpbD17ImxpbmUiOiA0MiwgImZpbGUiOiAiYXBwLmNvbmYifSkKICAgIAogICAgIyDmtYvor5Xkuozov5vliLbmlbDmja4KICAgIGJhZF9kYXRhID0gYidceGU2XHg5N1x4YTAnICAjIFVURi0457yW56CB55qEIuaXoCIKICAgIFNpbXBsZUxvZ2dlci53YXJuaW5nKCLml6DmlYjmlbDmja7mtYEiLCBiYWRfZGF0YSwgc2VjdG9yPVsweDEyLCAweGZmLCAweDdmXSkKICAgIAogICAgIyDmtYvor5XltYzlpZflj4LmlbAKICAgIFNpbXBsZUxvZ2dlci5kZWJ1Zygi6LCD6K+V5L+h5oGvIiwgeyJrZXkiOiBbMSwgMiwgM119LCB0aW1lb3V0PTMwLjUp