V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
maemo
V2EX  ›  Python

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

  •  
  •   maemo · 2017-12-29 11:29:05 +08:00 · 3888 次点击
    这是一个创建于 2550 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

    demo 的前端界面如下:
    fs

    有 5 个 gunicorn 进程:
    gunicorn

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

    gunicorn

    系统 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"
            }
        }
    }
    
    第 1 条附言  ·  2017-12-29 15:05:30 +08:00

    刚才试着配置了 gunicorn 的 threads , worker不用 meinheld。可以满足需求了。
    不过大家有试过用异步worker,实现这样的功能吗

    5 条回复    2017-12-29 12:59:54 +08:00
    wcsjtu
        1
    wcsjtu  
       2017-12-29 11:43:20 +08:00
    看 gunicorn 官方文档呗,应该有 worker 间通信的方式的。
    反正 uwsgi 有 signal 来实现 worker 间通信
    maemo
        2
    maemo  
    OP
       2017-12-29 12:43:16 +08:00
    @wcsjtu #1 #1 能否大概讲下 uwsgi worker 之间怎么通信呢?我之前用 uwsgi, 4 个 worker 也是这样的问题
    wcsjtu
        3
    wcsjtu  
       2017-12-29 12:54:20 +08:00   ❤️ 1
    shellfly
        4
    shellfly  
       2017-12-29 12:54:42 +08:00   ❤️ 1
    可以把这个设置独立到一个不同进程都能读到的地方,比如丢到缓存里,然后让每个进程读取这个配置
    maemo
        5
    maemo  
    OP
       2017-12-29 12:59:54 +08:00
    @shellfly #4 #4 哦,我感觉问题在于 logger, 我是用 logger = logging.getLogger('django_docker') 这样来获取,但是这样获取到的是只是这一个 process 的 logger 实例
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5930 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 02:53 · PVG 10:53 · LAX 18:53 · JFK 21:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.