-- edit --
This answer was originally written for Amazon Linux AMI, which has now reached end-of-life.
To keeps things clear and separate, I wrote a new answer for Amazon Linux 2.
-- original answer --
Summary
The simplest solution, in my opinion, is to log to the /opt/python/log
folder, as suggested by bewestphal and by @thierry-j (under steve-dunlop's answer).
That is also what the official AWS EB Python Sample Application does: see python-v1.zip
source
The log file will then be included automatically when you request logs from EB.
This solution works out-of-the-box, without any modification of .ebextensions
, as long as you do not call django-admin.py
(or other django code) in your .ebextensions
.
However, most apps do need to call django-admin.py
in .ebextensions
, e.g. in order to migrate
. That will cause the log file to be created prematurely, with root
owner and root
group. This leads to permission errors, because the app runs as wsgi:wsgi
.
This can be fixed by adding a new command, at the end of your container_commands
, to remove the "premature" log file, e.g.:
container_commands:
...
9999_remove_root_log_file:
command: rm /opt/python/log/django.log
ignoreErrors: true
Details below.
Background
On a standard pre-configured Amazon Linux/Python platform, which uses Apache with mod_wsgi (see AWS platform docs), the WSGIDaemonProcess
for the Django app runs as user wsgi
and group wsgi
(see /etc/httpd/conf.d/wsgi.conf
on your EC2 instance).
In addition, the default folder permissions for the /opt/python/log
folder (on my standard EC2 instance) are: drwxrwxr-x 3 root wsgi 4096 Mar 5 14:08 .
That is, the wsgi
group has all permissions (rwx
), so the Django app (group wsgi
) can create log files there.
This works, out-of-the-box, as demonstrated by the official AWS EB Python Sample Application (python-v1.zip).
However, if you do anything in your .ebextensions
that causes the logging
file-handler to be initialized (like calling django-admin.py
), it will break.
Permission issues
Here's how using django-admin.py
in .ebextensions
breaks your log file permissions:
Elastic Beanstalk container_commands
, in .ebextensions
, are executed as the root
user (see aws docs).
If you call django-admin.py
in any of the container_commands
, e.g. with collectstatic
or migrate
, that will cause your logging file handler(s) to be initialized.
If the specified log file does not exist yet, at that time, it will be created, with root
owner and root
group.
That means the Django app, running as part of the wsgi
group, will not have permission to write to the log file (which belongs to the root
group).
This leads to permission errors, e.g.: PermissionError: [Errno 13] Permission denied: '/opt/python/log/django.log'
How to reproduce
The following snippet illustrates the permissions issue and shows how to fix it.
To reproduce the issue, add these container_commands
to a clean project (e.g. following the AWS EB Django tutorial), configure Django settings.py
to log to /opt/python/log/django.log
, deploy to AWS EB, then check the eb-activity.log
to see the output of the container commands.
...
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
DRY solution
So, there is no need to mess with file/folder permissions explicitly.
If you don't call django code in .ebextensions
, logging to /opt/python/log
works, out-of-the-box.
If you do call django code in .ebextensions
, e.g. django-admin.py collectstatic
, simply remove the log file at the end of your container_commands
section.
NOTE: If you want to log files to persist between deployments, only remove them if they are owned by root
.
Here's a DRY example:
In .ebextensions
config:
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
and in 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
...