From 7403679ee79ed154791addb17693714b16d26375 Mon Sep 17 00:00:00 2001 From: Burhan Khalid Date: Mon, 27 Jul 2015 18:42:23 +0300 Subject: [PATCH 1/4] fixing an allauth setting bug --- README.rst | 4 +- cookiecutter.json | 1 + {{cookiecutter.repo_name}}/README.rst | 12 +++ .../config/settings/common.py | 2 - .../config/settings/production.py | 78 +++++++++++++++++-- {{cookiecutter.repo_name}}/config/wsgi.py | 6 ++ .../requirements/production.txt | 6 ++ 7 files changed, 101 insertions(+), 8 deletions(-) diff --git a/README.rst b/README.rst index 119d801c..5ea8d6b6 100644 --- a/README.rst +++ b/README.rst @@ -24,11 +24,12 @@ Features * Registration via django-allauth_ * Procfile_ for deploying to Heroku * Grunt build for compass and livereload -* Basic e-mail configurations for send emails via Mailgun_ +* Basic e-mail configurations for sending emails via Mailgun_ * Media storage using Amazon S3 * Serve static files from Amazon S3 or Whitenoise_ (optional) * Pre configured Celery_ (optional) * Integration with Maildump_ for local email testing (optional) +* Integration with Sentry_ for error logging (optional) .. _Bootstrap: https://github.com/twbs/bootstrap .. _AngularJS: https://github.com/angular/angular.js @@ -41,6 +42,7 @@ Features .. _Whitenoise: https://whitenoise.readthedocs.org/ .. _Celery: http://www.celeryproject.org/ .. _Maildump: https://github.com/ThiefMaster/maildump +.. _Sentry: https://getsentry.com Constraints diff --git a/cookiecutter.json b/cookiecutter.json index da0a2c94..b10b7390 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -12,5 +12,6 @@ "use_whitenoise": "y", "use_celery": "n", "use_maildump": "n", + "use_sentry": "n", "windows": "n" } diff --git a/{{cookiecutter.repo_name}}/README.rst b/{{cookiecutter.repo_name}}/README.rst index 786232f5..532e28f5 100644 --- a/{{cookiecutter.repo_name}}/README.rst +++ b/{{cookiecutter.repo_name}}/README.rst @@ -40,6 +40,9 @@ Environment Variable Django Setting Development DJANGO_AWS_ACCESS_KEY_ID AWS_ACCESS_KEY_ID n/a raises error DJANGO_AWS_SECRET_ACCESS_KEY AWS_SECRET_ACCESS_KEY n/a raises error DJANGO_AWS_STORAGE_BUCKET_NAME AWS_STORAGE_BUCKET_NAME n/a raises error +{% if cookiecutter.use_sentry == "y" -%}DJANGO_SENTRY_DSN SENTRY_DSN n/a raises error +DJANGO_SENTRY_CLIENT SENTRY_CLIENT n/a raven.contrib.django.raven_compat.DjangoClient +DJANGO_SENTRY_LOG_LEVEL SENTRY_LOG_LEVEL n/a logging.INFO{%- endif %} DJANGO_MAILGUN_API_KEY MAILGUN_ACCESS_KEY n/a raises error DJANGO_MAILGUN_SERVER_NAME MAILGUN_SERVER_NAME n/a raises error ======================================= =========================== ============================================== ====================================================================== @@ -148,6 +151,15 @@ To stop the email server:: The email server listens on 127.0.0.1:1025 {% endif %} +{% if cookiecutter.use_sentry == "y" %} +Sentry +^^^^^^ + +Sentry is an error logging aggregator service. You can sign up for a free account at http://getsentry.com or download and host it yourself. +The system is setup with reasonable defaults, including 404 logging and integration with the WSGI application. + +You must set the DSN url in production. +{% endif %} It's time to write the code!!! diff --git a/{{cookiecutter.repo_name}}/config/settings/common.py b/{{cookiecutter.repo_name}}/config/settings/common.py index 22d3d084..fb494848 100644 --- a/{{cookiecutter.repo_name}}/config/settings/common.py +++ b/{{cookiecutter.repo_name}}/config/settings/common.py @@ -152,8 +152,6 @@ TEMPLATES = [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', - 'allauth.account.context_processors.account', - 'allauth.socialaccount.context_processors.socialaccount', 'django.template.context_processors.i18n', 'django.template.context_processors.media', 'django.template.context_processors.static', diff --git a/{{cookiecutter.repo_name}}/config/settings/production.py b/{{cookiecutter.repo_name}}/config/settings/production.py index ab9a7054..ce5db9e5 100644 --- a/{{cookiecutter.repo_name}}/config/settings/production.py +++ b/{{cookiecutter.repo_name}}/config/settings/production.py @@ -5,11 +5,13 @@ Production Configurations - Use djangosecure - Use Amazon's S3 for storing static files and uploaded media - Use mailgun to send emails -- Use MEMCACHIER on Heroku +- Use Redis on Heroku ''' +{% if cookiecutter.use_sentry == "y" %} +import raven +{% endif %} from __future__ import absolute_import, unicode_literals - from boto.s3.connection import OrdinaryCallingFormat from django.utils import six @@ -29,10 +31,25 @@ SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') # ------------------------------------------------------------------------------ INSTALLED_APPS += ("djangosecure", ) -MIDDLEWARE_CLASSES = ( - # Make sure djangosecure.middleware.SecurityMiddleware is listed first +{% if cookiecutter.use_sentry == "y" -%} +# raven sentry client +# See https://docs.getsentry.com/hosted/clients/python/integrations/django/ +INSTALLED_APPS += ('raven.contrib.django.raven_compat', ) +{%- endif %} + +SECURITY_MIDDLEWARE = ( 'djangosecure.middleware.SecurityMiddleware', -) + MIDDLEWARE_CLASSES +) + +{% if cookiecutter.use_sentry == "y" -%} +RAVEN_MIDDLEWARE = ('raven.contrib.django.raven_compat.middleware.Sentry404CatchMiddleware', + 'raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware',) +MIDDLEWARE_CLASSES = SECURITY_MIDDLEWARE + RAVEN_MIDDLEWARE + MIDDLEWARE_CLASSES +{%- endif %} + +# Make sure djangosecure.middleware.SecurityMiddleware is listed first +MIDDLEWARE_CLASSES = SECURITY_MIDDLEWARE + MIDDLEWARE_CLASSES + # set this to 60 seconds and then to 518400 when you can prove it works SECURE_HSTS_SECONDS = 60 @@ -138,4 +155,55 @@ CACHES = { } } +{% if cookiecutter.use_sentry == "y" %} +# Sentry Configuration +SENTRY_CLIENT = env('DJANGO_SENTRY_CLIENT') +LOGGING = { + 'version': 1, + 'disable_existing_loggers': True, + 'root': { + 'level': 'WARNING', + 'handlers': ['sentry'], + }, + 'formatters': { + 'verbose': { + 'format': '%(levelname)s %(asctime)s %(module)s ' + '%(process)d %(thread)d %(message)s' + }, + }, + 'handlers': { + 'sentry': { + 'level': 'ERROR', + 'class': 'raven.contrib.django.raven_compat.handlers.SentryHandler', + }, + 'console': { + 'level': 'DEBUG', + 'class': 'logging.StreamHandler', + 'formatter': 'verbose' + } + }, + 'loggers': { + 'django.db.backends': { + 'level': 'ERROR', + 'handlers': ['console'], + 'propagate': False, + }, + 'raven': { + 'level': 'DEBUG', + 'handlers': ['console'], + 'propagate': False, + }, + 'sentry.errors': { + 'level': 'DEBUG', + 'handlers': ['console'], + 'propagate': False, + }, + }, +} +SENTRY_CELERY_LOGLEVEL = env('DJANGO_SENTRY_LOG_LEVEL', logging.INFO) +RAVEN_CONFIG = { + 'CELERY_LOGLEVEL': env('DJANGO_SENTRY_LOG_LEVEL', logging.INFO) +} +{% endif %} + # Your production stuff: Below this line define 3rd party library settings diff --git a/{{cookiecutter.repo_name}}/config/wsgi.py b/{{cookiecutter.repo_name}}/config/wsgi.py index cf104ade..47f60dd4 100644 --- a/{{cookiecutter.repo_name}}/config/wsgi.py +++ b/{{cookiecutter.repo_name}}/config/wsgi.py @@ -19,6 +19,9 @@ from django.core.wsgi import get_wsgi_application {% if cookiecutter.use_whitenoise == 'y' -%} from whitenoise.django import DjangoWhiteNoise {%- endif %} +{% if cookiecutter.use_sentry == "y" -%} +from raven.contrib.django.raven_compat.middleware.wsgi import Sentry +{%- endif %} # We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks # if running multiple sites in the same mod_wsgi process. To fix this, use @@ -36,6 +39,9 @@ application = get_wsgi_application() # See: https://whitenoise.readthedocs.org/ application = DjangoWhiteNoise(application) {%- endif %} +{% if cookiecutter.use_sentry == "y" -%} +application = Sentry(application) +{%- endif %} # Apply WSGI middleware here. # from helloworld.wsgi import HelloWorldApplication diff --git a/{{cookiecutter.repo_name}}/requirements/production.txt b/{{cookiecutter.repo_name}}/requirements/production.txt index b30edce5..30f70f1f 100644 --- a/{{cookiecutter.repo_name}}/requirements/production.txt +++ b/{{cookiecutter.repo_name}}/requirements/production.txt @@ -18,3 +18,9 @@ Collectfast==0.2.3 # Mailgun Support # --------------- django-mailgun==0.2.2 + +{% if cookiecutter.use_sentry == "y" -%} +# Raven is the Sentry client +# -------------------------- +raven +{%- endif %} From 69398a8292b976360df0fd9fd4aca1015c48c0b6 Mon Sep 17 00:00:00 2001 From: Burhan Khalid Date: Tue, 28 Jul 2015 19:02:41 +0300 Subject: [PATCH 2/4] fixing production settings logic for middleware --- {{cookiecutter.repo_name}}/config/settings/production.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/{{cookiecutter.repo_name}}/config/settings/production.py b/{{cookiecutter.repo_name}}/config/settings/production.py index ce5db9e5..2261b9a5 100644 --- a/{{cookiecutter.repo_name}}/config/settings/production.py +++ b/{{cookiecutter.repo_name}}/config/settings/production.py @@ -45,11 +45,12 @@ SECURITY_MIDDLEWARE = ( RAVEN_MIDDLEWARE = ('raven.contrib.django.raven_compat.middleware.Sentry404CatchMiddleware', 'raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware',) MIDDLEWARE_CLASSES = SECURITY_MIDDLEWARE + RAVEN_MIDDLEWARE + MIDDLEWARE_CLASSES -{%- endif %} +{% else %} # Make sure djangosecure.middleware.SecurityMiddleware is listed first MIDDLEWARE_CLASSES = SECURITY_MIDDLEWARE + MIDDLEWARE_CLASSES +{%- endif %} # set this to 60 seconds and then to 518400 when you can prove it works SECURE_HSTS_SECONDS = 60 From a79e84553340666bbf393f6327c30cc522c7a771 Mon Sep 17 00:00:00 2001 From: Burhan Khalid Date: Tue, 28 Jul 2015 23:23:46 +0300 Subject: [PATCH 3/4] flake8 and misc fixes --- .../config/settings/production.py | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/{{cookiecutter.repo_name}}/config/settings/production.py b/{{cookiecutter.repo_name}}/config/settings/production.py index 2261b9a5..75fc2cd8 100644 --- a/{{cookiecutter.repo_name}}/config/settings/production.py +++ b/{{cookiecutter.repo_name}}/config/settings/production.py @@ -6,14 +6,18 @@ Production Configurations - Use Amazon's S3 for storing static files and uploaded media - Use mailgun to send emails - Use Redis on Heroku -''' {% if cookiecutter.use_sentry == "y" %} -import raven +- Use sentry for error logging {% endif %} +''' from __future__ import absolute_import, unicode_literals from boto.s3.connection import OrdinaryCallingFormat from django.utils import six +{% if cookiecutter.use_sentry == "y" %} +import raven +import logging +{% endif %} from .common import * # noqa @@ -31,7 +35,7 @@ SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') # ------------------------------------------------------------------------------ INSTALLED_APPS += ("djangosecure", ) -{% if cookiecutter.use_sentry == "y" -%} +{% if cookiecutter.use_sentry == "y" - %} # raven sentry client # See https://docs.getsentry.com/hosted/clients/python/integrations/django/ INSTALLED_APPS += ('raven.contrib.django.raven_compat', ) @@ -43,8 +47,9 @@ SECURITY_MIDDLEWARE = ( {% if cookiecutter.use_sentry == "y" -%} RAVEN_MIDDLEWARE = ('raven.contrib.django.raven_compat.middleware.Sentry404CatchMiddleware', - 'raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware',) -MIDDLEWARE_CLASSES = SECURITY_MIDDLEWARE + RAVEN_MIDDLEWARE + MIDDLEWARE_CLASSES + 'raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware',) +MIDDLEWARE_CLASSES = SECURITY_MIDDLEWARE + \ + RAVEN_MIDDLEWARE + MIDDLEWARE_CLASSES {% else %} # Make sure djangosecure.middleware.SecurityMiddleware is listed first @@ -54,9 +59,11 @@ MIDDLEWARE_CLASSES = SECURITY_MIDDLEWARE + MIDDLEWARE_CLASSES # set this to 60 seconds and then to 518400 when you can prove it works SECURE_HSTS_SECONDS = 60 -SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool("DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS", default=True) +SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool( + "DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS", default=True) SECURE_FRAME_DENY = env.bool("DJANGO_SECURE_FRAME_DENY", default=True) -SECURE_CONTENT_TYPE_NOSNIFF = env.bool("DJANGO_SECURE_CONTENT_TYPE_NOSNIFF", default=True) +SECURE_CONTENT_TYPE_NOSNIFF = env.bool( + "DJANGO_SECURE_CONTENT_TYPE_NOSNIFF", default=True) SECURE_BROWSER_XSS_FILTER = True SESSION_COOKIE_SECURE = False SESSION_COOKIE_HTTPONLY = True @@ -99,7 +106,8 @@ AWS_HEADERS = { AWS_EXPIRY, AWS_EXPIRY)) } -# URL that handles the media served from MEDIA_ROOT, used for managing stored files. +# URL that handles the media served from MEDIA_ROOT, used for managing +# stored files. MEDIA_URL = 'https://s3.amazonaws.com/%s/' % AWS_STORAGE_BUCKET_NAME # Static Assests @@ -111,7 +119,8 @@ STATICFILES_STORAGE = DEFAULT_FILE_STORAGE STATIC_URL = MEDIA_URL # See: https://github.com/antonagestam/collectfast -# For Django 1.7+, 'collectfast' should come before 'django.contrib.staticfiles' +# For Django 1.7+, 'collectfast' should come before +# 'django.contrib.staticfiles' AWS_PRELOAD_METADATA = True INSTALLED_APPS = ('collectfast', ) + INSTALLED_APPS {%- endif %} @@ -123,12 +132,14 @@ DEFAULT_FROM_EMAIL = env('DJANGO_DEFAULT_FROM_EMAIL', EMAIL_BACKEND = 'django_mailgun.MailgunBackend' MAILGUN_ACCESS_KEY = env('DJANGO_MAILGUN_API_KEY') MAILGUN_SERVER_NAME = env('DJANGO_MAILGUN_SERVER_NAME') -EMAIL_SUBJECT_PREFIX = env("DJANGO_EMAIL_SUBJECT_PREFIX", default='[{{cookiecutter.project_name}}] ') +EMAIL_SUBJECT_PREFIX = env( + "DJANGO_EMAIL_SUBJECT_PREFIX", default='[{{cookiecutter.project_name}}] ') SERVER_EMAIL = env('DJANGO_SERVER_EMAIL', default=DEFAULT_FROM_EMAIL) # TEMPLATE CONFIGURATION # ------------------------------------------------------------------------------ -# See: https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.loaders.cached.Loader +# See: +# https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.loaders.cached.Loader TEMPLATES[0]['OPTIONS']['loaders'] = [ ('django.template.loaders.cached.Loader', [ 'django.template.loaders.filesystem.Loader', From 4b0d35194f64ad68d4f46042ef283f7177dd7474 Mon Sep 17 00:00:00 2001 From: Burhan Khalid Date: Wed, 29 Jul 2015 00:02:57 +0300 Subject: [PATCH 4/4] making sure tests pass --- .../config/settings/production.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/{{cookiecutter.repo_name}}/config/settings/production.py b/{{cookiecutter.repo_name}}/config/settings/production.py index 75fc2cd8..23830a33 100644 --- a/{{cookiecutter.repo_name}}/config/settings/production.py +++ b/{{cookiecutter.repo_name}}/config/settings/production.py @@ -15,7 +15,6 @@ from __future__ import absolute_import, unicode_literals from boto.s3.connection import OrdinaryCallingFormat from django.utils import six {% if cookiecutter.use_sentry == "y" %} -import raven import logging {% endif %} @@ -24,7 +23,7 @@ from .common import * # noqa # SECRET CONFIGURATION # ------------------------------------------------------------------------------ # See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key -# Raises ImproperlyConfigured exception if DJANO_SECRET_KEY not in os.environ +# Raises ImproperlyConfigured exception if DJANGO_SECRET_KEY not in os.environ SECRET_KEY = env("DJANGO_SECRET_KEY") # This ensures that Django will be able to detect a secure connection @@ -34,17 +33,14 @@ SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') # django-secure # ------------------------------------------------------------------------------ INSTALLED_APPS += ("djangosecure", ) - -{% if cookiecutter.use_sentry == "y" - %} +{% if cookiecutter.use_sentry == "y" -%} # raven sentry client # See https://docs.getsentry.com/hosted/clients/python/integrations/django/ INSTALLED_APPS += ('raven.contrib.django.raven_compat', ) {%- endif %} - SECURITY_MIDDLEWARE = ( 'djangosecure.middleware.SecurityMiddleware', ) - {% if cookiecutter.use_sentry == "y" -%} RAVEN_MIDDLEWARE = ('raven.contrib.django.raven_compat.middleware.Sentry404CatchMiddleware', 'raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware',) @@ -132,8 +128,7 @@ DEFAULT_FROM_EMAIL = env('DJANGO_DEFAULT_FROM_EMAIL', EMAIL_BACKEND = 'django_mailgun.MailgunBackend' MAILGUN_ACCESS_KEY = env('DJANGO_MAILGUN_API_KEY') MAILGUN_SERVER_NAME = env('DJANGO_MAILGUN_SERVER_NAME') -EMAIL_SUBJECT_PREFIX = env( - "DJANGO_EMAIL_SUBJECT_PREFIX", default='[{{cookiecutter.project_name}}] ') +EMAIL_SUBJECT_PREFIX = env("DJANGO_EMAIL_SUBJECT_PREFIX", default='[{{cookiecutter.project_name}}] ') SERVER_EMAIL = env('DJANGO_SERVER_EMAIL', default=DEFAULT_FROM_EMAIL) # TEMPLATE CONFIGURATION @@ -142,9 +137,7 @@ SERVER_EMAIL = env('DJANGO_SERVER_EMAIL', default=DEFAULT_FROM_EMAIL) # https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.loaders.cached.Loader TEMPLATES[0]['OPTIONS']['loaders'] = [ ('django.template.loaders.cached.Loader', [ - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', - ]), + 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', ]), ] # DATABASE CONFIGURATION @@ -217,5 +210,4 @@ RAVEN_CONFIG = { 'CELERY_LOGLEVEL': env('DJANGO_SENTRY_LOG_LEVEL', logging.INFO) } {% endif %} - # Your production stuff: Below this line define 3rd party library settings