请教一个困扰很久的 pythong logging setLevel 的问题,项目是用 django + gunicorn + nginx 部署的

2017-12-29 11:29:05 +08:00
 maemo

有一个 django 项目,日志写入到文件,需求是可以动态修改 logging 的 level.

我写了一个 demo, 在请求中把每个 level 的 log 都打印一下,如果更改了 level, 那么后台打印就会看到。

demo 的前端界面如下:

有 5 个 gunicorn 进程:

我用 ab 命令测试了一下 ,后台打印的 log ,可以看到只有 PID:28763 的 loglevel 是 error ,其它的进程都还是默认的 debug level 。 也就是说设置 level 只对 一个进程生效,我想要的效果是对所有进程重新,大家能帮我找下原因吗,谢谢了。

系统 centos 7.4
Django: 1.11.8
nginx: 1.12
gunicorn: 19.7.1
meinheld: 0.6.1

django 的 log 配置部分:



LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '[%(process)d] [%(asctime)s] %(levelname)s [%(filename)s:%(lineno)s] %(message)s'
        }
    },
    'handlers': {
        'file': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'maxBytes': 1024*1024,
            'backupCount': 5,
            'filename': '/tmp/run.log',
            'formatter': 'verbose'
        },
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'verbose'
        }
    },
    'loggers': {
        'django_docker': {
            'handlers': ['file', 'console'],
            'level': 'DEBUG',
            'propagate': True,
        },
        'django.request': {
            'handlers': ['file'],
            'level': 'ERROR',
            'propagate': False,
        }
    },
}

django 中打印 log 的代码:


logger = logging.getLogger('django_docker')

def index(request):
    level_name = logging.getLevelName(logger.getEffectiveLevel())
    logger.critical('========= Start Logging ================')
    logger.debug('\t\t==> Debug Log')
    logger.info('\t\t==> Info Log')
    logger.warning('\t==> Warning Log')
    logger.error('\t\t==> Error Log')
    logger.critical('\t==> Critical Log')
    logger.critical('========= End Logging ================')
    if request.method == 'POST':
        if 'logLevel' in request.POST and request.POST['logLevel']:
            level_name = request.POST['logLevel'].upper()
            logger.critical('====> %s <===' % logger.root.name)
            logger.root.setLevel(level_name)
            logger.setLevel(level_name)
            return redirect('index')
    return render(request, 'main/index.html', {'log_level': level_name})

gunicorn 配置

import multiprocessing
from logging.config import dictConfig

name = "django_docker"
bind = "unix:/var/run/django_docker.sock"
worker_class = "egg:meinheld#gunicorn_worker"
#workers = multiprocessing.cpu_count() * 2 + 1
workers = 4
reload = True

umask = 0002
user = 'nginx'
group = 'nginx'

accesslog = "/tmp/gunicorn.access.log"
errorlog = "/tmp/gunicorn.error.log"

raw_env = ["DJANGO_SETTINGS_MODULE=django_docker.settings"]
chdir = " /home/tiannpen/workspace/django_docker/"
pidfile = "/var/run/gunicorn.pid"
daemon = True

capture_output = True

logconfig_dict = {
    'version':1,
    'disable_existing_loggers': False,
    'loggers':{
        "root": {"level": "INFO", "handlers": ["console"]},
        "gunicorn.error": {
            "level": "INFO",
            "handlers": ["error_file"],
            "propagate": 1,
            "qualname": "gunicorn.error"
        },

        "gunicorn.access": {
            "level": "INFO",
            "handlers": ["access_file"],
            "propagate": 0,
            "qualname": "gunicorn.access"
        }
    },
    'handlers':{
        "console": {
            "class": "logging.StreamHandler",
            "formatter": "generic",
            "stream": "sys.stdout"
        },
        "error_file": {
            "class": "logging.FileHandler",
            "formatter": "generic",
            "filename": "/tmp/gunicorn.error.log"
        },
        "access_file": {
            "class": "logging.handlers.RotatingFileHandler",
            "maxBytes": 1024*1024,
            "backupCount": 5,
            "formatter": "generic",
            "filename": "/tmp/gunicorn.access.log",
        }
    },
    'formatters':{
        "generic": {
            "format": "%(asctime)s [%(process)d] [%(levelname)s] %(message)s",
            "datefmt": "[%Y-%m-%d %H:%M:%S %z]",
            "class": "logging.Formatter"
        },
        "access": {
            "format": "%(message)s",
            "class": "logging.Formatter"
        }
    }
}
3872 次点击
所在节点    Python
5 条回复
wcsjtu
2017-12-29 11:43:20 +08:00
看 gunicorn 官方文档呗,应该有 worker 间通信的方式的。
反正 uwsgi 有 signal 来实现 worker 间通信
maemo
2017-12-29 12:43:16 +08:00
@wcsjtu #1 #1 能否大概讲下 uwsgi worker 之间怎么通信呢?我之前用 uwsgi, 4 个 worker 也是这样的问题
wcsjtu
2017-12-29 12:54:20 +08:00
shellfly
2017-12-29 12:54:42 +08:00
可以把这个设置独立到一个不同进程都能读到的地方,比如丢到缓存里,然后让每个进程读取这个配置
maemo
2017-12-29 12:59:54 +08:00
@shellfly #4 #4 哦,我感觉问题在于 logger, 我是用 logger = logging.getLogger('django_docker') 这样来获取,但是这样获取到的是只是这一个 process 的 logger 实例

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/418542

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX