From 67cefdcd529de6dc96f00c6ebbf307064fe3af9b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Stefan=20K=C3=B6gl?= Date: Sat, 2 Mar 2013 19:15:23 +0100 Subject: [PATCH] start implementation of proper logging Conflicts: mygpo/api/advanced/__init__.py --- mygpo/api/advanced/__init__.py | 17 +++++++------- mygpo/api/basic_auth.py | 8 +++++-- mygpo/api/legacy.py | 8 ++++--- mygpo/api/sanitizing.py | 8 ++++--- mygpo/api/simple.py | 7 ++++-- mygpo/settings.py | 53 ++++++++++++++++++++++++++++++++++++++++++ mygpo/userfeeds/auth.py | 1 - mygpo/users/sync.py | 8 ++++--- mygpo/web/forms.py | 6 +++-- mygpo/web/views/podcast.py | 6 +++-- 10 files changed, 96 insertions(+), 26 deletions(-) diff --git a/mygpo/api/advanced/__init__.py b/mygpo/api/advanced/__init__.py index af528f51..b43dd6d7 100644 --- a/mygpo/api/advanced/__init__.py +++ b/mygpo/api/advanced/__init__.py @@ -41,7 +41,6 @@ from mygpo.api.httpresponse import JsonResponse from mygpo.api.sanitizing import sanitize_url, sanitize_urls from mygpo.api.advanced.directory import episode_data, podcast_data from mygpo.api.backend import get_device, BulkSubscribe -from mygpo.log import log from mygpo.utils import parse_time, format_time, parse_bool, get_timestamp from mygpo.decorators import allowed_methods, repeat_on_conflict from mygpo.core import models @@ -62,6 +61,10 @@ from mygpo.db.couchdb.episode_state import get_podcasts_episode_states, \ episode_state_for_ref_urls, get_episode_actions +import logging +logger = logging.getLogger(__name__) + + # keys that are allowed in episode actions EPISODE_ACTION_KEYS = ('position', 'episode', 'action', 'device', 'timestamp', 'started', 'total', 'podcast') @@ -153,7 +156,7 @@ def update_subscriptions(user, device, add, remove): subscriber.execute() except BulkException as be: for err in be.errors: - log('Advanced API: %(username)s: Updating subscription for ' + loger.error('Advanced API: %(username)s: Updating subscription for ' '%(podcast_url)s on %(device_uid)s failed: ' '%(rerror)s (%(reason)s)'.format(username=user.username, podcast_url=err.doc, device_uid=device.uid, @@ -186,7 +189,7 @@ def episodes(request, username, version=1): actions = json.loads(request.body) except (JSONDecodeError, UnicodeDecodeError) as e: msg = 'Advanced API: could not decode episode update POST data for user %s: %s' % (username, e) - log(msg) + logger.warn(msg) return HttpResponseBadRequest(msg) log('start: user %s: %d actions from %s' % (request.user._id, len(actions), ua_string)) @@ -209,13 +212,11 @@ def episodes(request, username, version=1): try: update_urls = update_episodes(request.user, actions, now, ua_string) except DeviceUIDException as e: - import traceback - s = u'could not update episodes for user %s: %s %s: %s' % (username, e, traceback.format_exc(), actions) - log(s.decode('utf-8', errors='ignore')) + logger.warn('invalid device UID while uploading episode actions for user %s: %s' % (username, e)) return HttpResponseBadRequest(str(e)) + except InvalidEpisodeActionAttributes as e: - import traceback - log(u'could not update episodes for user %s: %s %s: %s' % (username, e, traceback.format_exc(), actions)) + logger.warn('invalid episode action attributes while uploading episode actions for user %s: %s' % (username, e)) return HttpResponseBadRequest(str(e)) log('done: user %s: %d actions from %s' % (request.user._id, len(actions), ua_string)) diff --git a/mygpo/api/basic_auth.py b/mygpo/api/basic_auth.py index 7c662fc7..ab5b805f 100644 --- a/mygpo/api/basic_auth.py +++ b/mygpo/api/basic_auth.py @@ -20,10 +20,13 @@ from functools import wraps from django.http import HttpResponse, HttpResponseBadRequest from django.contrib.auth import authenticate -from mygpo.log import log from mygpo.decorators import repeat_on_conflict +import logging +logger = logging.getLogger(__name__) + + @repeat_on_conflict(['user']) def login(request, user): from django.contrib.auth import login @@ -143,7 +146,8 @@ def check_username(protected_view): return protected_view(request, *args, username=username, **kwargs) else: - log('username in authentication (%s) and in requested resource (%s) don\'t match' % (request.user.username, username)) + # TODO: raise SuspiciousOperation here? + logger.warn('username in authentication (%s) and in requested resource (%s) don\'t match' % (request.user.username, username)) return HttpResponseBadRequest('username in authentication (%s) and in requested resource (%s) don\'t match' % (request.user.username, username)) return wrapper diff --git a/mygpo/api/legacy.py b/mygpo/api/legacy.py index c7404e25..e81abd76 100644 --- a/mygpo/api/legacy.py +++ b/mygpo/api/legacy.py @@ -22,7 +22,6 @@ from django.utils.datastructures import MultiValueDictKeyError from django.views.decorators.csrf import csrf_exempt from django.views.decorators.cache import never_cache -from mygpo.log import log from mygpo.api.sanitizing import sanitize_urls from mygpo.users.models import User from mygpo.api.opml import Importer, Exporter @@ -30,6 +29,9 @@ from mygpo.core.models import Podcast, SubscriptionException from mygpo.api.backend import get_device from mygpo.db.couchdb.podcast import podcast_for_url +import logging +logger = logging.getLogger(__name__) + LEGACY_DEVICE_NAME = 'Legacy Device' LEGACY_DEVICE_UID = 'legacy' @@ -74,7 +76,7 @@ def upload(request): try: p.subscribe(user, dev) except SubscriptionException as e: - log('Legacy API: %(username)s: could not subscribe to podcast %(podcast_url)s on device %(device_id)s: %(exception)s' % + logger.warn('Legacy API: %(username)s: could not subscribe to podcast %(podcast_url)s on device %(device_id)s: %(exception)s' % {'username': user.username, 'podcast_url': p.url, 'device_id': dev.id, 'exception': e}) for r in rem: @@ -82,7 +84,7 @@ def upload(request): try: p.unsubscribe(user, dev) except SubscriptionException as e: - log('Legacy API: %(username): could not unsubscribe from podcast %(podcast_url) on device %(device_id): %(exception)s' % + logger.warn('Legacy API: %(username): could not unsubscribe from podcast %(podcast_url) on device %(device_id): %(exception)s' % {'username': user.username, 'podcast_url': p.url, 'device_id': dev.id, 'exception': e}) return HttpResponse('@SUCCESS', mimetype='text/plain') diff --git a/mygpo/api/sanitizing.py b/mygpo/api/sanitizing.py index d514f3a7..1bc9fe04 100644 --- a/mygpo/api/sanitizing.py +++ b/mygpo/api/sanitizing.py @@ -5,12 +5,14 @@ import re from django.core.cache import cache from mygpo.core import models -from mygpo.log import log from mygpo.utils import iterate_together, progress from mygpo.db.couchdb.podcast import podcast_count, podcast_for_oldid, \ all_podcasts from mygpo.db.couchdb.common import sanitizingrules_by_obj_type +import logging +logger = logging.getLogger(__name__) + def sanitize_urls(urls, obj_type='podcast'): """ Apply sanitizing rules to the given URLs and return the results """ @@ -111,7 +113,7 @@ def maintenance(dry_run=False): if not su_podcast: # "target" podcast does not exist, we simply change the url if not dry_run: - log('updating podcast %s - "%s" => "%s"' % (p.id, p.url, su)) + logger.info('updating podcast %s - "%s" => "%s"' % (p.id, p.url, su)) p.url = su p.save() @@ -141,7 +143,7 @@ def maintenance(dry_run=False): def rewrite_podcasts(p_old, p_new): - log('merging podcast %s "%s" to correct podcast %s "%s"' % (p_old.id, p_old.url, p_new.id, p_new.url)) + logger.info('merging podcast %s "%s" to correct podcast %s "%s"' % (p_old.id, p_old.url, p_new.id, p_new.url)) rewrite_newpodcast(p_old, p_new) diff --git a/mygpo/api/simple.py b/mygpo/api/simple.py index f47ce7a0..8f15a285 100644 --- a/mygpo/api/simple.py +++ b/mygpo/api/simple.py @@ -42,7 +42,6 @@ from mygpo.directory.toplist import PodcastToplist from mygpo.directory.models import ExamplePodcasts from mygpo.api.advanced.directory import podcast_data from mygpo.directory.search import search_podcasts -from mygpo.log import log from mygpo.decorators import allowed_methods from mygpo.utils import parse_range from mygpo.core.json import json, JSONDecodeError @@ -50,6 +49,10 @@ from mygpo.db.couchdb import BulkException from mygpo.db.couchdb.podcast import podcasts_by_id from mygpo.db.couchdb.user import suggestions_for_user +import logging +logger = logging.getLogger(__name__) + + ALLOWED_FORMATS = ('txt', 'opml', 'json', 'jsonp', 'xml') def check_format(fn): @@ -224,7 +227,7 @@ def set_subscriptions(urls, user, device_uid, user_agent): errors = subscriber.execute() except BulkException as be: for err in be.errors: - log('Simple API: %(username)s: Updating subscription for ' + logger.warn('Simple API: %(username)s: Updating subscription for ' '%(podcast_url)s on %(device_uid)s failed: ' '%(error)s (%(reason)s)'.format(username=user.username, podcast_url=err.doc, device_uid=device.uid, diff --git a/mygpo/settings.py b/mygpo/settings.py index 342adfb1..9fdd9dd5 100644 --- a/mygpo/settings.py +++ b/mygpo/settings.py @@ -199,6 +199,59 @@ MAINTENANCE = os.path.exists(os.path.join(BASE_DIR, 'MAINTENANCE')) EMAIL_BACKEND = 'django_couchdb_utils.email.backends.CouchDBEmailBackend' + +LOGGING = { + 'version': 1, + 'disable_existing_loggers': True, + 'formatters': { + 'verbose': { + 'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s' + }, + 'simple': { + 'format': '%(levelname)s %(message)s' + }, + }, + 'handlers': { + 'null': { + 'level': 'DEBUG', + 'class': 'django.utils.log.NullHandler', + }, + 'console':{ + 'level': 'DEBUG', + 'class': 'logging.StreamHandler', + 'formatter': 'simple' + }, + 'mail_admins': { + 'level': 'ERROR', + 'class': 'django.utils.log.AdminEmailHandler', + }, + 'file': { + 'level': 'DEBUG', + 'class':'logging.handlers.RotatingFileHandler', + 'filename': '/var/log/mygpo/mygpo.log', + 'maxBytes': 10000000, + 'backupCount': 10, + 'formatter': 'verbose', + }, + }, + 'loggers': { + 'django': { + 'handlers': ['console'], + 'propagate': True, + 'level': 'WARN', + }, + 'django.request': { + 'handlers': ['mail_admins'], + 'level': 'ERROR', + 'propagate': False, + }, + 'mygpo': { + 'handlers': ['console', 'mail_admins', 'file'], + 'level': 'INFO', + } + } +} + # minimum number of subscribers a podcast must have to be assigned a slug PODCAST_SLUG_SUBSCRIBER_LIMIT = 10 diff --git a/mygpo/userfeeds/auth.py b/mygpo/userfeeds/auth.py index 55f6018b..ca0a6759 100644 --- a/mygpo/userfeeds/auth.py +++ b/mygpo/userfeeds/auth.py @@ -20,7 +20,6 @@ from functools import wraps from django.http import HttpResponse, HttpResponseBadRequest, Http404 from mygpo.users.models import User -from mygpo.log import log ############################################################################# diff --git a/mygpo/users/sync.py b/mygpo/users/sync.py index f1ddf609..bbd5a104 100644 --- a/mygpo/users/sync.py +++ b/mygpo/users/sync.py @@ -3,9 +3,11 @@ from collections import namedtuple from couchdbkit.ext.django.schema import * from mygpo.core.models import Podcast, SubscriptionException -from mygpo.log import log from mygpo.db.couchdb.podcast import podcasts_to_dict +import logging +logger = logging.getLogger(__name__) + GroupedDevices = namedtuple('GroupedDevices', 'is_synced devices') @@ -170,7 +172,7 @@ class SyncedDevicesMixin(DocumentSchema): try: podcast.subscribe(self, device) except SubscriptionException as e: - log('Web: %(username)s: cannot sync device: %(error)s' % + logger.warn('Web: %(username)s: cannot sync device: %(error)s' % dict(username=self.username, error=repr(e))) for podcast_id in rem: @@ -181,7 +183,7 @@ class SyncedDevicesMixin(DocumentSchema): try: podcast.unsubscribe(self, device) except SubscriptionException as e: - log('Web: %(username)s: cannot sync device: %(error)s' % + logger.warn('Web: %(username)s: cannot sync device: %(error)s' % dict(username=self.username, error=repr(e))) diff --git a/mygpo/web/forms.py b/mygpo/web/forms.py index 3d9b5299..2feee346 100644 --- a/mygpo/web/forms.py +++ b/mygpo/web/forms.py @@ -4,9 +4,11 @@ from django import forms from django.utils.translation import ugettext as _ from mygpo.api.constants import DEVICE_TYPES -from mygpo.log import log from mygpo.users.models import Device +import logging +logger = logging.getLogger(__name__) + class UserAccountForm(forms.Form): """ @@ -142,7 +144,7 @@ class SyncForm(forms.Form): in the form. """ if not self.is_valid(): - log('no target given in SyncForm') + logger.warn('no target given in SyncForm') raise ValueError(_('No device selected')) target = self.cleaned_data['targets'] diff --git a/mygpo/web/views/podcast.py b/mygpo/web/views/podcast.py index a7f4c5d0..b73b1745 100644 --- a/mygpo/web/views/podcast.py +++ b/mygpo/web/views/podcast.py @@ -19,7 +19,6 @@ from mygpo.users.models import HistoryEntry, DeviceDoesNotExist, SubscriptionAct from mygpo.web.forms import SyncForm from mygpo.decorators import allowed_methods, repeat_on_conflict from mygpo.web.utils import get_podcast_link_target, get_page_list -from mygpo.log import log from mygpo.db.couchdb.episode import episodes_for_podcast from mygpo.db.couchdb.podcast import podcast_for_slug, podcast_for_slug_id, \ podcast_for_oldid, podcast_for_url @@ -29,6 +28,9 @@ from mygpo.db.couchdb.episode_state import get_podcasts_episode_states, \ episode_listener_counts from mygpo.db.couchdb.directory import tags_for_user, tags_for_podcast +import logging +logger = logging.getLogger(__name__) + MAX_TAGS_ON_PAGE=50 @@ -303,7 +305,7 @@ def unsubscribe(request, podcast, device_uid): try: podcast.unsubscribe(request.user, device) except SubscriptionException as e: - log('Web: %(username)s: could not unsubscribe from podcast %(podcast_url)s on device %(device_id)s: %(exception)s' % + logger.warn('Web: %(username)s: could not unsubscribe from podcast %(podcast_url)s on device %(device_id)s: %(exception)s' % {'username': request.user.username, 'podcast_url': podcast.url, 'device_id': device.id, 'exception': e}) return HttpResponseRedirect(return_to) -- 2.11.4.GIT