我在自定义python logger中创建了一个包装器,以在日志格式化程序中添加其他属性。
logFormat = logging.Formatter('[%(levelname)s],[%(asctime)-15s], %(API_SERVER)s, %(funcName)s,%(lineno)d, %(message)s')
附加属性 - > API_SERVER
日志将包装器方法显示为funcName而不是实际的funcName。
[DEBUG],[2017-05-23 17:52:13,865], jupiter-api-server, loggingMethodsWrapper,91, Response returned from DolphinD is 200, returning status success, to caller.
包装代码 - >
def loggingMethodsWrapper(self, logLevelMethod, *kargs):
# Calling method logging methods dynamcially
# Add the parameters in the extra if you want to add
# more columns in logging format
getattr(self.log, logLevelMethod)(
*kargs, extra={'API_SERVER': self.API_SERVER})
答案 0 :(得分:0)
发生了错误的函数名称,因为loggingMethodsWrapper
实际上正在进行日志调用。
你想要的似乎是调用loggingMethodsWrapper的函数。修复方法是更改格式化程序,使其不包含%(funcName)s
并将其移动为传递给%(message)s
的参数的一部分或作为额外参数。
这样做,一个肮脏的修复就是让你的包装器走上堆栈并抓住下一个功能。
在python2中,这就是:
caller = inspect.stack()[1][3]
在python3上,这将是:
caller = inspect.stack()[1].filename
所以:
logFormat = logging.Formatter('[%(levelname)s],[%(asctime)-15s], %(API_SERVER)s, %(CALLER)s,%(lineno)d, %(message)s')
...
def loggingMethodsWrapper(self, logLevelMethod, *kargs):
caller = # python-specific method of getting caller
getattr(self.log, logLevelMethod)(
*kargs, extra={'CALLER' : caller, 'API_SERVER': self.API_SERVER})
如果您可以更改调用者,则可以进行简单修复 - 将函数名称传递给记录器包装器
loggingMethodsWrapper(self, func_name, logLevelMethod, *kargs):
....
然后当你打电话时
def foo():
loggingMethodsWrapper(foo.__name__, log_level, ...)
答案 1 :(得分:0)
Log.py
class Log(Singleton):
log = None
caller = None
def __init__(self):
### Configure log
# TODO: The config has to come from Dictconfig YAML file
logFolder = CONSTANTS['LOG']['DIR']
self.API_SERVER = API_SERVER
caller = inspect.stack()[1][3]
print caller
self.log = logging.getLogger(__name__)
# If handlers are already set donot do it again
if not len(self.log.handlers):
logFormat = logging.Formatter('[%(levelname)s],[%(asctime)-15s], %(API_SERVER)s, %(caller)s,%(lineno)d, %(message)s')
def loggingMethodsWrapper(self, logLevelMethod, *kargs):
# Calling method logging methods dynamically
# Add the parameters in the extra if you want to add
# more columns in logging format
getattr(self.log, logLevelMethod)(
*kargs, extra={'API_SERVER': self.API_SERVER, 'caller': self.caller})
示例API文件 - >
from flask import Flask, Response, request
from base import base
from jupiter_api.lib.jupFlaskClassy import *
from jupiter_api.business.accounts import accounts as bzAccounts
from jupiter_api.business.role_decorators import permGate, login_required
from flask.ext.cors import CORS
from jupiter_api.utils.log import Log
Log = Log()
class accounts(base):
supported_methods = "OPTIONS, GET, POST, DELETE"
## GET request to pull all user accounts
@route('/<userId>/<companyId>/accounts/<accountId>', methods=['GET'])
@permGate('list_accounts')
@login_required
def get_details(self, userId, companyId, accountId):
#import pdb; pdb.set_trace()
Log.debug("In get accounts for user")
# Validate arguments
if not userId or not companyId:
return self.invalidData()
# Print arguments
Log.debug("Getting account details for user %s ", userId)
注意 - 我有100个类似于调用Log()的Accounts API的API。
答案 2 :(得分:0)
您可以使用inspect
包来获取先前函数的名称。这是一个记录功能的单例包装器示例,显示了“ true”调用者:
import logging
import inspect
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class MyLogger(metaclass=Singleton):
logger = None
def __init__(self):
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(threadName)s - %(message)s",
handlers=[
logging.StreamHandler()
])
self.logger = logging.getLogger(__name__ + '.logger')
@staticmethod
def __get_call_info():
stack = inspect.stack()
# stack[1] gives previous function (info in our case)
# stack[2] gives before previous function and so on
fn = stack[2][1]
ln = stack[2][2]
func = stack[2][3]
return fn, func, ln
def info(self, message, *args):
message = "{} - {} at line {}: {}".format(*self.__get_call_info(), message)
self.logger.info(message, *args)