需求:
分布式运行项目时,要日志记录中跟踪源IP地址与运行主机,以便更好的通过日志快速定位分析问题。
不借助django日志场景:
# 可以通过添加自定义日志过滤器和格式化程序来实现这一点,该过滤器和格式化程序将主机名放入日志消息中
import logging, platform
class HostnameFilter(logging.Filter):
hostname = platform.node() # 获取主机名
def filter(self, record):
record.hostname = HostnameFilter.hostname
return True
handler = logging.StreamHandler()
handler.addFilter(HostnameFilter())
handler.setFormatter(logging.Formatter('%(asctime)s %(hostname)s: %(message)s', datefmt='%b %d %H:%M:%S'))
logger = logging.getLogger()
logger.addHandler(handler)
logger.setLevel(logging.INFO)
logger.info('Hello, world!')
借助django日志场景:
1、自定义中间件
# 自定义中间件
import threading
import logging
import socket
try:
from django.utils.deprecation import MiddlewareMixin
except ImportError:
MiddlewareMixin = object
local = threading.local()
class RequestLogFilter(logging.Filter):
"""
日志过滤器,将当前请求线程的request信息保存到日志的record上下文
record带有formater需要的信息。
"""
def filter(self, record):
record.hostname = getattr(local, 'hostname', None) # 主机名称
record.dest_ip = getattr(local, 'dest_ip', None) # 服务器IP
record.username = getattr(local, 'username', None) # 用户
record.source_ip = getattr(local, 'source_ip', None) # 客户端IP
return True
class RequestLogMiddleware(MiddlewareMixin):
"""
将request的信息记录在当前的请求线程上。
"""
def process_request(self, request):
local.hostname = socket.gethostname()
local.dest_ip = socket.gethostbyname(local.hostname)
local.username = request.user
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR', '')
if x_forwarded_for:
source_ip = x_forwarded_for.split(',')[0] # 所以这里是真实的ip
else:
source_ip = request.META.get('REMOTE_ADDR') # 这里获得代理ip
local.source_ip = source_ip
def process_response(self, request, response):
return response
2、settings.py
MIDDLEWARE新增中间件 ''firmware_manage.middlewares.RequestLogMiddleware'
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'firmware_manage.middlewares.RequestLogMiddleware', # 自定义中间件 firmware_manage是app
]
# 日志文件配置
LOGGING = {
'version': 1,
'disable_existing_loggers': True, # 是否禁用已经存在的日志器
'formatters': { # 日志信息显示的格式
'verbose': {'format': '[%(asctime)s %(levelname)s [%(module)s:%(lineno)d] [%(process)d:%(threadName)s] %(message)s'},
'simple': {'format': '%(asctime)s %(levelname)s [%(module)s:%(lineno)d] %(message)s'},
'complex': {'format': '[%(hostname)s source_ip:%(source_ip)s] [%(asctime)s %(levelname)s [%(module)s:%(lineno)d] [%(process)d:%(threadName)s] %(message)s'},
},
'filters': {
'new_add': {
'()': 'firmware_manage.middlewares.RequestLogFilter',
},
},
'handlers': { # 日志处理方法
'console': { # 向终端中输出日志
'level': 'INFO',
'filters': ['new_add'],
'class': 'logging.StreamHandler',
'formatter': 'complex'
},
},
'loggers': {
'django': { # 定义了一个名为django的日志器
'handlers': ['console'], # 可以同时向终端与文件中输出日志
'level': 'INFO', # 日志器接收的最低日志级别
'propagate': False, # 是否继承父类的log信息,0:否 1:是
},
}
}
3、视图函数使用
import logging
logger = logging.getLogger("django")
@require_POST
def get_tasks(request):
"""
func:
任务管理页搜索
"""
logger.info("in get tasks...")
data = json.loads(request.body)
4、测试结果
非k8s部署,日志中携带主机名、客户端IP:
k8s部署,日志中携带运行的deployment、客户端IP:
参考:
https://www.cnpython.com/qa/296606 Python日志如何在日志中跟踪主机名?
https://www.cnblogs.com/yuzhen0228/p/12015877.html django 自定义日志字段