使用python(django)记录AWS Elastic Beanstalk

use*_*167 22 python django amazon-web-services amazon-elastic-beanstalk

如何在AWS弹性beanstalk中管理应用程序日志?我是说你把应用程序日志写到哪个文件?我在我的开发环境中使用以下日志记录配置,但是当我在AWS中部署时,这不起作用.

提前致谢!

DEBUG_LOG_DIR = BASE_DIR + "/django_debug.log"
LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    # How to format the output
    'formatters': {
        'standard': {
            'format' : "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
            'datefmt' : "%d/%b/%Y %H:%M:%S"
        },
    },
    # Log handlers (where to go)
    'handlers': {
        'null': {
            'level':'DEBUG',
            'class':'django.utils.log.NullHandler',
        },
        'log_file': {
            'level':'DEBUG',
            'class':'logging.handlers.RotatingFileHandler',
            'filename': DEBUG_LOG_DIR,
            'maxBytes': 50000,
            'backupCount': 2,
            'formatter': 'standard',
        },
        'console':{
            'level':'INFO',
            'class':'logging.StreamHandler',
            'formatter': 'standard'
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
        },
    },
    # Loggers (where does the log come from)
    'loggers': {
        'repackager': {
            'handlers': ['console', 'log_file'],
            'level': 'DEBUG',
            'propagate': True,
        },
        'django': {
            'handlers':['console'],
            'propagate': True,
            'level':'WARN',
        },
        'django.db.backends': {
            'handlers': ['console', 'log_file'],
            'level': 'WARN',
            'propagate': False,
        },
        '': {
            'handlers': ['console', 'log_file'],
            'level': 'DEBUG',
        },
    }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*lop 26

我有一个类似的问题,但在Elastic Beanstalk上,所以我在.ebextensions应用程序的文件夹中创建了一个配置文件(例如applogs.config).这将创建app-logs文件夹(如果它尚不存在)并设置文件权限和所有者,以便应用程序可以在其中写入其日志.

commands:
  00_create_dir:
    command: mkdir -p /var/log/app-logs
  01_change_permissions:
    command: chmod g+s /var/log/app-logs
  02_change_owner:
    command: chown wsgi:wsgi /var/log/app-logs
Run Code Online (Sandbox Code Playgroud)

最后,在您的Django设置中:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': '/var/log/app-logs/django.log',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['file'],
            'level': 'DEBUG',
            'propagate': True,
        },
    },
}
Run Code Online (Sandbox Code Playgroud)

另外,如果您希望使用Web从beanstalk日志访问日志,请将其添加到.ebextensions中的文件中

files:
  "/opt/elasticbeanstalk/tasks/taillogs.d/django.conf":
    mode: "000755"
    owner: root
    group: root
    content: |
      /var/log/app-logs/django.log
Run Code Online (Sandbox Code Playgroud)

  • 对于带有 Gunicorn 的 Amazon Linux 2,用户和组从 wsgi:wsgi 更改为 webapp:webapp (8认同)
  • 在我的设置ID中必须使用另一个用户:`command:chown wsgi:wsgi/var/log/app-logs` (7认同)
  • 实际上最好使用`/opt/python/log/` 作为日志。目录已经存在,无需创建,获取日志包或保存到cloudwatch时打包。 (3认同)
  • 如另一个答案中所建议,我添加了以下内容以避免一个最终的权限错误:`03_change_default_owner:命令:setfacl -d -mg :: rw / var / log / app-logs` (2认同)
  • 我打了几个小时,以了解为什么这对我不起作用。我得到了:ValueError:无法配置处理程序'file':[Errno 13]权限被拒绝:'/var/log/app-logs/django.log'原来是因为日志文件已经存在,我需要使我的chmod和chown递归。希望这对某人有帮助。 (2认同)

use*_*167 12

好的,我想出了办法.

首先我通过ssh连接到ec2机器,然后在/ var/log中创建一个名为app_logs的文件夹,其中包含root用户:

mkdir /var/log/app_logs
Run Code Online (Sandbox Code Playgroud)

之后我做了以下事情:

cd /var/log/
chmod g+s app_logs/
setfacl -d -m g::rw app_logs/
chown wsgi:wsgi app_logs/
Run Code Online (Sandbox Code Playgroud)

这可以确保在此文件夹中创建的所有文件都将wsgi作为所有者,并且可以为该文件所属的组写入.我不得不这样做,因为我注意到django app创建的日志文件具有root作为所有者和所有者组,但应用程序通过wsgi用户运行.

最后我将DEBUG_LOG_DIR更改为/var/log/app_logs/django_debug.log

  • 请记住,如果您需要重建实例,则需要再次手动执行.这也不适用于自动缩放的实例. (6认同)

小智 5

有一种不需要任何 beanstalk 配置的简单方法。

LOGGING下的 Django 设置中,设置一个指向文件 '/opt/python/log/{log_file_name}' 的处理程序。然后可以通过“日志”下的 beanstalk 环境菜单访问日志。

LOGGING = {
    ...,
    'handlers': {
        'logfile': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': '/opt/python/log/{log_file_name}',
        },
    },
    'loggers': {
        'debugger': {
            'level': 'DEBUG',
            'handlers': ['logfile'],
        'propagate': False,
    },
}
Run Code Online (Sandbox Code Playgroud)

此位置在此处的文档中说明:

https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features.logging.html#health-logs-instancelocation

  • 我同意这是理想的解决方案。但是当我尝试实现此操作时,我收到一条错误,指出生成的日志文件(django.log)的权限被拒绝。如果我通过 SSH 进入盒子并 chmod 777 django.log 文件,它就可以正常工作。然而,这不是一个可接受的解决方案。 (2认同)

djv*_*jvg 5

- 编辑 -

这个答案最初被写了亚马逊的Linux AMI,目前已达到了结束生命

为了让事情清楚和分开,我Amazon Linux 2写了一个新答案

——原答案——

概括

在我看来,最简单的解决方案是/opt/python/log按照bewestphal和 @ thierry -j 的建议(在steve-dunlop 的回答下)登录到文件夹。

这也是官方 AWS EB Python示例应用程序所做的:请参阅python-v1.zip 源代码

当您从 EB 请求日志时,日志文件将自动包含在内。

该解决方案的工作外的开箱,没有任何修饰.ebextensions,只要你django-admin.py(或其他Django的代码)在你的.ebextensions

然而,大多数应用程序需要调用django-admin.py.ebextensions,比如为了migrate。这将导致过早创建具有root所有者和root组的日志文件。这会导致权限错误,因为应用程序以wsgi:wsgi.

这可以通过的 末尾添加一个新命令来解决container_commands,以删除“过早”日志文件,例如:

container_commands:
  ...
  9999_remove_root_log_file:
    command: rm /opt/python/log/django.log
    ignoreErrors: true
Run Code Online (Sandbox Code Playgroud)

详情如下。

背景

在标准的预配置 Amazon Linux/Python 平台上,该平台使用 Apache 和 mod_wsgi(请参阅AWS 平台文档),WSGIDaemonProcessDjango 应用程序以用户wsgi和组身份运行wsgi(请参阅/etc/httpd/conf.d/wsgi.conf您的 EC2 实例)。

此外,文件夹的默认文件夹权限/opt/python/log(在我的标准 EC2 实例上)是:drwxrwxr-x 3 root wsgi 4096 Mar 5 14:08 .

也就是说,该wsgi组拥有所有权限 ( rwx),因此 Django 应用程序 (组wsgi) 可以在那里创建日志文件。

正如官方 AWS EB Python 示例应用程序 ( python-v1.zip)所演示的那样,这是开箱即用的 ) 所示。

但是,如果你在你.ebextensionslogging文件中做了任何导致文件处理程序被初始化的事情(比如调用django-admin.py),它就会中断。

权限问题

以下是使用django-admin.pyin.ebextensions破坏日志文件权限的方法:

Elastic Beanstalk container_commands, in .ebextensions,作为root用户执行(请参阅aws docs)。

如果您调用django-admin.py任何container_commands,例如使用collectstaticmigrate,这将导致您的日志文件处理程序被初始化。如果指定的日志文件尚不存在,则届时将创建它,并带有root所有者和root组。

这意味着作为wsgi组的一部分运行的 Django 应用程序将无权写入日志文件(属于该root组)。

这会导致权限错误,例如: PermissionError: [Errno 13] Permission denied: '/opt/python/log/django.log'

如何繁殖

以下代码段说明了权限问题并展示了如何修复它。

要重现该问题,请将这些添加container_commands到一个干净的项目中(例如遵循AWS EB Django 教程),将 Django 配置settings.py为登录到/opt/python/log/django.log,部署到 AWS EB,然后检查eb-activity.log以查看容器命令的输出。

...

container_commands:
  0100_show_current_user:
    # show that we are running as root user
    command: whoami
  0200_try_to_remove_log_file:
    # we need a clean slate for this example (make sure no log file owned by wsgi is present)
    command: rm /opt/python/log/django.log
    ignoreErrors: true
  0300_break_log_file_permissions:
    # this causes a new log file to be created, owned by root:root (instead of wsgi:wsgi)
    command: django-admin.py
  0400_show_log_file_permissions:
    # prove that a log file was created by root, and show folder permissions
    command: ls -la /opt/python/log
  0500_fix_by_removing_log_file_after_all_django_admin_calls:
    # remove the log file created by django-admin.py, to ensure that a new log file will  
    # be created when the server starts, owned by wsgi:wsgi
    command: rm /opt/python/log/django.log
    ignoreErrors: true
Run Code Online (Sandbox Code Playgroud)

干燥溶液

因此,没有必要明确地弄乱文件/文件夹权限

如果您不在 中调用 django 代码.ebextensions/opt/python/log则开箱即用。

如果您确实在 中调用 django 代码.ebextensions,例如django-admin.py collectstatic,只需删除您部分末尾的日志文件container_commands

注意:如果要在部署之间保留日志文件,请仅在它们归root.

这是一个 DRY 示例:

.ebextensions配置中:

option_settings:
  # create EB environment property for the log file path
  aws:elasticbeanstalk:application:environment:
    LOG_FILE_PATH: /opt/python/log/django.log
...

container_commands:
  ...
  # django code called here, e.g. "django-admin.py collectstatic"
  ...
  9999_remove_any_existing_django_log_files:
    command: rm $LOG_FILE_PATH      
    ignoreErrors: true
Run Code Online (Sandbox Code Playgroud)

并在settings.py

...
# get log path from environment variable, with fallback for local development
log_file_path = os.getenv('LOG_FILE_PATH', 'local.log')
# use this as 'filename' for the file handler, as described in the other answers
...
Run Code Online (Sandbox Code Playgroud)