部署在ECS的Django自定义日志无法显示在CloudWatch的问题
问题解决:ECS上Django自定义日志无法显示在CloudWatch
问题背景
部署在ECS的Django项目中,自定义日志记录器ru_profile的日志完全无法在AWS CloudWatch Logs中显示,仅能看到botocore、urllib3及root日志记录器的内容。
当前配置与使用情况
Django日志配置
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'json': { 'format': '%(levelname)s %(asctime)s %(name)s %(message)s %(lineno)d %(pathname)s', 'class': 'pythonjsonlogger.jsonlogger.JsonFormatter', }, }, 'handlers': { 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', 'formatter': 'json', }, }, 'loggers': { 'django': { 'handlers': ['console'], 'level': 'INFO', 'propagate': True, }, 'ru_profile': { 'handlers': ['console'], 'level': 'DEBUG', 'propagate': False, }, '': { 'handlers': ['console'], 'level': 'DEBUG', 'propagate': True, }, }, 'root': { 'handlers': ['console'], 'level': 'DEBUG', }, }
日志使用示例
import logging logger = logging.getLogger('ru_profile') class ForgotPasswordView(CreateView): model = User template_name = 'user/forgot_password.html' form_class = ForgotPasswordForm def form_valid(self, form): phone = str(form.cleaned_data['phone']) user = User.find_by_phone(phone) if user is not None: user.send_reset_pin() logger.info(f"Reset PIN sent successfully to {phone}") else: logger.error(f"Couldn't reset PIN, user not found for phone '{phone}'") django_messages.error(self.request, _("Couldn't reset your PIN. Please try again")) return self.form_invalid(form) return redirect('reset_pin_view', phone=phone)
额外信息
- Dockerfile已添加
ENV PYTHONUNBUFFERED=1 print()语句可正常显示在CloudWatch- 测试过不同日志级别,自定义日志均无输出
- 应用通过uwsgi+supervisord运行
解决步骤
1. 修复Django日志配置冲突
你的配置中同时存在空字符串日志器('')和root日志器,二者本质指向同一个root logger,会导致配置冲突,干扰自定义日志器的输出。删除空字符串日志器配置,修改后的LOGGING如下:
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'json': { 'format': '%(levelname)s %(asctime)s %(name)s %(message)s %(lineno)d %(pathname)s', 'class': 'pythonjsonlogger.jsonlogger.JsonFormatter', }, }, 'handlers': { 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', 'formatter': 'json', }, }, 'loggers': { 'django': { 'handlers': ['console'], 'level': 'INFO', 'propagate': True, }, 'ru_profile': { 'handlers': ['console'], 'level': 'DEBUG', 'propagate': False, }, }, 'root': { 'handlers': ['console'], 'level': 'DEBUG', }, }
2. 调整uwsgi配置,确保日志输出到stdout
uwsgi默认可能屏蔽或重定向应用日志,需明确配置将日志发送到标准输出。修改uwsgi.ini或启动命令:
# uwsgi.ini示例配置 [uwsgi] socket = :8000 module = myproject.wsgi:application master = true processes = 4 # 关键配置:将日志输出到stdout stdout-logger = true disable-logging = false logto = /dev/stdout
如果用命令行启动,添加参数:
uwsgi --ini uwsgi.ini --logto /dev/stdout --disable-logging false
3. 配置supervisord转发应用日志到控制台
supervisord需要正确捕获应用的stdout和stderr,确保输出能被ECS收集并发送到CloudWatch。修改supervisord程序配置:
[program:django] command = uwsgi --ini uwsgi.ini directory = /path/to/your/project user = root # 转发stdout和stderr到控制台,不做日志轮转 stdout_logfile = /dev/stdout stdout_logfile_maxbytes = 0 stderr_logfile = /dev/stderr stderr_logfile_maxbytes = 0 # 将stderr合并到stdout(可选,方便统一收集) redirect_stderr = true
4. 容器内测试日志输出,定位问题环节
进入运行中的容器,手动触发日志输出,确认应用本身能正常输出:
# 进入容器 docker exec -it <container-id> /bin/bash # 启动Django shell python manage.py shell
在shell中执行:
import logging logger = logging.getLogger('ru_profile') logger.info("Test custom log message")
如果控制台能看到这条日志,说明Django日志配置没问题,问题出在uwsgi/supervisord的日志转发;如果看不到,继续检查是否有其他地方覆盖了LOGGING设置。
内容的提问来源于stack exchange,提问作者arturkuchynski
相关产品推荐
相关产品推荐

