【问题标题】:AWS Elastic Beanstalk logging with python (django)使用 python (django) 进行 AWS Elastic Beanstalk 日志记录
【发布时间】:2015-02-17 14:39:49
【问题描述】:

您如何在 AWS elastic 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',
        },
    }
}

【问题讨论】:

    标签: python django amazon-web-services amazon-elastic-beanstalk amazon-linux-2


    【解决方案1】:

    我在 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
    

    最后,在您的 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,
            },
        },
    }
    

    此外,如果您希望通过网络从 beanstalk 日志访问您的日志,请将其添加到您的 .ebextensions 文件中

    files:
      "/opt/elasticbeanstalk/tasks/taillogs.d/django.conf":
        mode: "000755"
        owner: root
        group: root
        content: |
          /var/log/app-logs/django.log
    

    【讨论】:

    • 在我的设置中必须使用另一个用户:command: chown wsgi:wsgi /var/log/app-logs
    • 对日志使用/opt/python/log/ 实际上更好。该目录已经存在,无需创建,获取日志包或保存到cloudwatch时打包。
    • 按照另一个答案的建议,我添加了以下内容以避免最终权限错误:03_change_default_owner: command: setfacl -d -m g::rw /var/log/app-logs
    • 我想了好几个小时才知道为什么这对我不起作用。我得到: ValueError: Unable to configure handler 'file': [Errno 13] Permission denied: '/var/log/app-logs/django.log' 原来是因为日志文件已经存在,我需要使我的 chmod 和 chown 递归。希望这对某人有所帮助。
    • 使用 gunicorn 的 Amazon Linux 2 的注意事项,用户和组从 wsgi:wsgi 更改为 webapp:webapp
    【解决方案2】:

    好的,我想出了一个办法。

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

    mkdir /var/log/app_logs
    

    之后我做了以下操作:

    cd /var/log/
    chmod g+s app_logs/
    setfacl -d -m g::rw app_logs/
    chown wsgi:wsgi app_logs/
    

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

    最后我把 DEBUG_LOG_DIR 改成了 /var/log/app_logs/django_debug.log

    【讨论】:

    • 请记住,如果您需要重建实例,则需要再次手动执行。这也不会应用于自动缩放的实例。
    • 您可以将 .ebextensions 中的命令作为命令在应用程序启动之前执行以确保它始终处于打开状态
    【解决方案3】:

    有一种简单的方法,不需要任何 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,
        },
    }
    

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

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

    【讨论】:

    • 我同意这是理想的解决方案。但是当我尝试实现这一点时,我收到一条错误消息,指出生成的日志文件(django.log)的权限被拒绝。如果我 SSH 进入盒子并 chmod 777 django.log 文件,它工作正常。然而,这不是一个可接受的解决方案。
    • 如果您遇到这样的权限问题,一种方法是制作具有写入权限的 EC2 启动脚本
    • 这使得答案的第一句话“有一种简单的方法不需要任何 beanstalk 配置”,不正确。
    • @JamesParker:您的权限错误的可能原因below
    • AL2 有类似的位置吗?
    【解决方案4】:

    -- 编辑--

    此答案最初是为 Amazon Linux AMI 编写的,现在已达到 end-of-life

    为了保持清晰和独立,我写了一个new answer for Amazon Linux 2

    -- 原始答案--

    总结

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

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

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

    只要您不要在您的.ebextensions 中调用django-admin.py(或其他django 代码),此解决方案开箱即用,无需对.ebextensions 进行任何修改.

    但是,大多数应用确实需要在 .ebextensions 中调用 django-admin.py,例如为了migrate。这将导致过早创建日志文件,其中包含root 所有者和root 组。这会导致权限错误,因为应用程序以wsgi:wsgi 运行。

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

    container_commands:
      ...
      9999_remove_root_log_file:
        command: rm /opt/python/log/django.log
        ignoreErrors: true
    

    详情如下。

    背景

    在标准的预配置 Amazon Linux/Python 平台上,该平台使用 Apache 和 mod_wsgi(请参阅 AWS platform docs),Django 应用程序的 WSGIDaemonProcess 以用户 wsgi 和组 wsgi 的身份运行(请参阅 @987654348 @ 在您的 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) 所展示的那样,这是开箱即用的。

    但是,如果您在 .ebextensions 中执行任何导致 logging 文件处理程序被初始化的事情(例如调用 django-admin.py),它将中断。

    权限问题

    .ebextensions 中使用django-admin.py 会破坏您的日志文件权限:

    Elastic Beanstalk container_commands.ebextensions 中以root 用户身份执行(请参阅aws docs)。

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

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

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

    如何重现

    以下 sn-p 说明了权限问题并说明了如何解决它。

    要重现该问题,请将这些 container_commands 添加到干净的项目中(例如,在 AWS EB Django tutorial 之后),配置 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
    

    干溶液

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

    如果您不调用 .ebextensions 中的 django 代码,则登录到 /opt/python/log 可以开箱即用。

    如果您确实在.ebextensions 中调用 django 代码,例如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
    

    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
    ...
    

    【讨论】:

    • 请注意:这在 Amazon Linux AMI 上(对我来说)有效,但我还没有在 Amazon Linux 2 上测试它(还)
    • 它不适用于开箱即用的 Amazon Linux 2。可能是因为没有 /opt/python/log (或 /opt/python )。我仍在尝试查看推荐的日志位置在哪里。我可能会回到 /var/log/,创建一个 app-logs 子文件夹。
    • @Oded:根据有关migrating to Amazon Linux 2 的AWS 文档,该应用程序现在位于/var/app/current。请参阅 Python 部分。
    • 知道了。实际上,我喜欢在重新安装应用程序时不破坏我的日志,因此我可以在调试问题时比较以前版本中发生的情况。
    • @Oded:我不确定/opt/python/log 是否有同样方便的替代方案。我在 AWS 文档中找不到任何建议,但 Amazon Linux 2 上 EB 的官方 Python 示例应用程序现在记录到 /tmp 文件夹,并使用自定义记录任务来包含这些日志。有关详细信息,请参阅更新的答案。
    【解决方案5】:

    此答案仅适用于 Amazon Linux 2。还没有迁移的yet,请看我的old answer for Amazon Linux AMI

    背景

    Amazon linux 2official AWS Python sample-application 使用 /tmp 文件夹进行日志记录。

    但是,当从 Elastic Beanstalk 请求日志时,添加到 /tmp 的自定义日志文件不会自动包含在内。要包含自定义日志文件,我们需要在 EC2 实例上的 /opt/elasticbeanstalk/tasks 的子文件夹中创建日志记录任务。请参阅文档中的instructions

    示例应用程序 (source) 使用 .ebextensions 完成此操作。但是,AWS Linux 2 migration docs 建议我们应该使用 .platform 挂钩:

    我们建议使用平台挂钩在您的环境实例上运行自定义代码。您仍然可以在 .ebextensions 配置文件中使用命令和容器命令,但使用起来并不容易。例如,在 YAML 文件中编写命令脚本可能很麻烦且难以测试。

    这还有一个额外的好处,即平台挂钩的输出被收集在一个单独的日志文件中,即。 /var/log/eb-hooks.log,让调试更简单。

    Amazon Linux 2 上的基本 Django 应用程序的 DRY 日志记录设置

    日志级别和日志路径在一个位置定义,作为 Elastic Beanstalk 环境属性,例如在.ebextensions/options.config:

    option_settings:
      aws:elasticbeanstalk:application:environment:
        LOG_LEVEL: INFO
        DJANGO_LOG_FILE_PATH: /tmp/django-app.log
        ...
    

    DJANGO_LOG_FILE_PATH 环境属性现在可以在平台挂钩中用于创建日志记录任务:

    .platform/hooks/postdeploy/020_create_logging_tasks.sh

    #!/bin/bash
    TASKS_DIR=/opt/elasticbeanstalk/tasks
    # include all app log files in bundle logs (replaces ".log" by "*")
    echo "${DJANGO_LOG_FILE_PATH//.log/*}" > "$TASKS_DIR/bundlelogs.d/01-app-log.conf"
    # include current app log file in tail logs
    echo $DJANGO_LOG_FILE_PATH > "$TASKS_DIR/taillogs.d/01-app-log.conf"
    

    请注意,平台挂钩需要执行权限,例如chmod +x 020_create_logging_tasks.sh。在 Windows 上,您可以使用 git,如 here 所述。

    为了防止权限问题,我们使用另一个平台挂钩来确保日志文件始终归webapp 所有。注意这个钩子在 logging-tasks 钩子之前运行:

    .platform/hooks/postdeploy/010_create_log_file.sh

    #!/bin/bash
    
    if test -f "$DJANGO_LOG_FILE_PATH";
    then
      echo "$DJANGO_LOG_FILE_PATH exists"
    else
      # create log file
      touch $DJANGO_LOG_FILE_PATH
    fi
    
    # set log file owner (we are currently "root", but the app runs as "webapp")
    chown webapp:webapp $DJANGO_LOG_FILE_PATH
    

    我们还在 Django 设置中使用 LOG_LEVELDJANGO_LOG_FILE_PATH 环境属性:

    settings.py

    ...
    # basic logging with file rotation ()
    log_level = os.getenv('LOG_LEVEL', 'INFO')
    handlers = dict(file={'class': 'logging.handlers.TimedRotatingFileHandler',
                          'filename': os.getenv('DJANGO_LOG_FILE_PATH'),
                          'when': 'midnight',
                          'interval': 1,
                          'backupCount': 1,
                          'encoding': 'utf-8'})
    loggers = dict(django=dict(level=log_level, handlers=['file']),
                   myapp=dict(level=log_level, handlers=['file']))
    LOGGING = dict(version=1,
                   disable_existing_loggers=False,
                   handlers=handlers,
                   loggers=loggers)
    ...
    

    一些注意事项:

    • 我们通常也会指定自定义 formatters,但为了清楚起见,我省略了这些。

    • 现在可以在/var/app/current 的 EC2 实例上找到应用程序本身。另请参阅extending EB Linux platforms 了解更多详情。

    • 应用程序现在以 webapp 的身份运行,组为 webapp

    • eb ssh 是你的朋友。见docs

    • 我们还使用平台挂钩来运行 Django 的 migratecollectstatic 命令,如 here 所述。

    编辑:

    正如 cmets 中的 @hax0 所指出的,如果您尝试在 EC2 实例上使用 SSH 运行 manage.py 命令,部署后可能会出现文件权限问题>.

    例如使用eb ssh时,你以ec2-user登录,但日志文件归webapp用户所有,并且默认只有所有者拥有写权限(644) .因此,当以ec2-user 运行python manage.py 时,您将收到一条错误消息,指出它无法配置日志文件处理程序,因为权限被拒绝。

    一个快速而肮脏的解决方法是临时更改文件权限,例如使用

    sudo chmod 646 /tmp/django-app.log
    

    另一种解决方法是以webapp 用户身份运行manage.py,例如:

    sudo su - webapp <<'EOF'
    source $(find /var/app/venv/*/bin/activate)
    export $(/opt/elasticbeanstalk/bin/get-config --output YAML environment | 
             sed -r 's/: /=/' | xargs)
    python3 /var/app/current/manage.py showmigrations
    EOF
    
    

    【讨论】:

    • 部署工作,但是当我们 ssh 进入实例并尝试python manage.py shell,它在/tmp/django-app.log 文件上给出了权限错误
    • @hax0:是的,我可以确认这一点。这是因为您是ec2-user,而日志文件属于webapp(用户和组)。默认情况下,只有日志文件所有者(即webapp)具有写权限(644)。如果这是偶然的,一个快速而肮脏的解决方法是临时更改文件权限,例如sudo chmod 646 /tmp/django-app.log。如果它是结构性的,你可以在 .platform 钩子中做类似的事情。请记住任何安全隐患。更好的选择可能是尝试以webapp 运行命令。
    • @hax0: manage.py shell 在更改文件权限后为我工作。我确实设法以webapp 用户的身份运行其他manage.py 命令,但无法让manage.py shell 以这种方式工作。请参阅答案中的编辑。
    • 在 Amazon Linux 2 上使用这个确切的解决方案,部署失败(Gunicorn + Django + Nginx)并显示 Permission denied: '/tmp/django-app.log'。这可能是因为manage.py 命令在container_commands 中运行。
    • django-app.log 似乎是模式 0600,由 root:root 拥有。我相信这是因为其他一些命令必须由 root 用户运行,它会生成 root 拥有的文件。 (再次假设这是 container_commands 中的内容,但可能是其他内容。)
    【解决方案6】:

    作为 linux 权限方面的初学者,我花了一些时间才让它工作。总结以上给出的答案,以下终于对我有用:

    日志记录配置

    commands:
      00_create_dir:
        command: mkdir -p /var/log/app-logs
      01_change_permissions:
        command: chmod g+s /var/log/app-logs
      02_change_default_owner:
        command: setfacl -d -m g::rw /var/log/app-logs
      03_change_owner:
        command: chown wsgi:wsgi /var/log/app-logs
    

    settings.py

    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,
        },
    },
    }
    

    这样,我可以使用“eb 日志”或在 Beanstalk 环境中的“日志”部分将日志视为单独的部分。

    【讨论】:

      【解决方案7】:

      在 elasticbeanstalk 中默认情况下,您可以在此处查看 django 错误日志。

      /var/log/httpd/error_log
      

      【讨论】:

      • 不,Django 服务器错误不会显示在此文件中。
      • 他们可能结束,但这只是在某些情况下。
      • 在 AWS 论坛上查看 this discussion
      猜你喜欢
      • 2015-12-14
      • 2021-03-22
      • 2021-03-09
      • 2021-03-10
      • 2019-02-11
      • 2015-01-14
      • 2017-04-04
      • 2011-09-07
      • 1970-01-01
      相关资源
      最近更新 更多