我正试图让Celery日志工作与 Django
. 我已将记录设置在 settings.py
转到控制台(由于我的主机是在 "我的主机 "上,所以工作正常。Heroku
). 在每个模块的顶部,我有。
import logging
logger = logging.getLogger(__name__)
而在我的tasks.py中,我有:
from celery.utils.log import get_task_logger
logger = get_task_logger(__name__)
这对记录一个任务的调用很有效,我得到了这样的输出。
2012-11-13T18:05:38+00:00 app[worker.1]: [2012-11-13 18:05:38,527: INFO/PoolWorker-2] Syc feed is starting
但如果这个任务调用了另一个模块中的方法,例如一个 queryset
方法,我就会得到重复的日志条目,比如说。
2012-11-13T18:00:51+00:00 app[worker.1]: [INFO] utils.generic_importers.ftp_processor process(): File xxx.csv already imported. Not downloaded
2012-11-13T18:00:51+00:00 app[worker.1]: [2012-11-13 18:00:51,736: INFO/PoolWorker-6] File xxx.csv already imported. Not downloaded
我想我可以使用
CELERY_HIJACK_ROOT_LOGGER = False
只需使用 Django
日志,但当我尝试时,这并不奏效,而且即使我让它工作,我也会失去了 "PoolWorker-6"
位,这是我想要的。顺便说一下,我不知道如何让任务名显示在Celery的日志条目中,因为它是 文献 似乎表明它应该)。)
我怀疑我漏掉了一些简单的东西。
当你的日志记录器在 "另一个模块 "的开头初始化时,它会链接到另一个日志记录器。它处理你的消息。它可以是根记录器,或者通常我在Django项目中看到的--记录器的名字是 ''
.
最好的方法是覆盖你的日志配置。
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'simple': {
'format': '%(levelname)s %(message)s',
'datefmt': '%y %b %d, %H:%M:%S',
},
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
'celery': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler',
'filename': 'celery.log',
'formatter': 'simple',
'maxBytes': 1024 * 1024 * 100, # 100 mb
},
},
'loggers': {
'celery': {
'handlers': ['celery', 'console'],
'level': 'DEBUG',
},
}
}
from logging.config import dictConfig
dictConfig(LOGGING)
在这种情况下,我想它应该像你假设的那样工作。
P.S. 在Python2.7+中添加了dictConfig。
Celery干扰根日志器是很麻烦的(这不是最佳实践,也无法完全控制),但它不会以任何方式禁用你的应用程序的自定义日志器,所以使用你自己的处理程序名称并定义你自己的行为,而不是试图用Celery来解决这个问题。反正我喜欢把我的应用程序的日志记录分开)。 你可以使用单独的处理程序,或者对Django代码和Celery任务使用相同的处理程序,你只需要在你的Django LOGGING配置中定义它们。 为了保证安全性,在formatter中添加模块、文件名和processName的格式化args,以帮助你区分消息的来源。
[这假定你已经在LOGGING设置值中为'yourapp'设置了一个指向Appender的处理程序--听起来你已经意识到了这一点]。
views.py
log = logging.getLogger('yourapp')
def view_fun():
log.info('about to call a task')
yourtask.delay()
任务.py
log = logging.getLogger('yourapp')
@task
def yourtask():
log.info('doing task')
对于Celery生成的日志--如果需要的话,使用celeryd标志--logfile将Celery的输出(例如,worker init,started task,task failed)发送到一个单独的地方。 或者,使用这里的另一个答案,将'celery'记录器发送到你选择的文件。
注意:我不会使用RotatingFileHandlers - 它们不支持多进程应用程序。 从另一个工具(如logrotate)进行日志轮换是比较安全的,从Django进行日志记录也是如此,假设你有多个进程,或者与芹菜工人共享相同的日志文件。 如果你使用的是多服务器的解决方案,你可能希望在某个地方集中记录。
为了解决重复的日志问题,我的做法是在声明我的settings.LOGGING dict时,将传播设置为false。
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose'
},
},
'formatters': {
'verbose': {
'format': '%(asctime)s %(levelname)s module=%(module)s, '
'process_id=%(process)d, %(message)s'
}
},
'loggers': {
'my_app1': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': False #this will do the trick
},
'celery': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': True
},
}
}
假设你的django项目布局是:my_project - tasks.py - email.py。
假设你的一个任务调用了email.py中的某个函数,那么日志记录将发生在email.py中,然后日志记录将被传播到 "父 "中,在这种情况下,父就是你的芹菜任务。因此,双重日志记录。但是,如果将某一日志记录器的传播设置为 "False",则意味着对于该日志记录器来说,它的日志不会传播到父日志记录器,因此不会有 "双重 "日志记录。
这里有一个 链接到Django文档 关于父子记录器的部分
也许能帮到大家,我的问题是把芹菜的日志都发到graylog。下面是解决方案。
celery.py:
app.config_from_object('django.conf:settings', namespace='CELERY')
# ====== Magic starts
from celery.signals import setup_logging
@setup_logging.connect
def config_loggers(*args, **kwargs):
from logging.config import dictConfig
from django.conf import settings
dictConfig(settings.LOGGING)
# ===== Magic ends
# Load task modules from all registered Django app configs.
app.autodiscover_tasks()
Settings. py:
LOGGING = {
'version': 1,
'handlers': {
'graypy': {
'class': 'graypy.GELFTCPHandler',
'host': GRAYLOG_HOST,
'port': GRAYLOG_PORT,
}
},
'loggers': {
'my_project': {
'handlers': ['graypy'],
'level': 'INFO',
},
# ====== Magic starts
'celery': {
'handlers': ['graypy'],
'level': 'INFO',
}
# ===== Magic ends
}
}