manager.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. # Multi-db support based on http://www.eflorenzano.com/blog/post/easy-multi-database-support-django/
  2. # TODO: is there a way to use the traceback module based on an exception variable?
  3. from django.conf import settings
  4. from django.db import models
  5. from django.conf import settings
  6. from django.db.models import sql
  7. from django.db.transaction import savepoint_state
  8. from django.utils.hashcompat import md5_constructor
  9. from django.utils.encoding import smart_unicode
  10. from django.db.models.sql import BaseQuery
  11. from django.db.models.query import QuerySet
  12. try:
  13. import thread
  14. except ImportError:
  15. import dummy_thread as thread
  16. import traceback
  17. import socket
  18. import warnings
  19. import datetime
  20. import django
  21. django_is_10 = django.VERSION < (1, 1)
  22. """
  23. ``DBLOG_DATABASE`` allows you to use a secondary database for error logging::
  24. DBLOG_DATABASE = dict(
  25. DATABASE_ENGINE='mysql', # defaults to settings.DATABASE_ENGINE
  26. DATABASE_NAME='my_db_name',
  27. DATABASE_USER='db_user',
  28. DATABASE_PASSWORD='db_pass',
  29. DATABASE_HOST='localhost', # defaults to localhost
  30. DATABASE_PORT='', # defaults to [default port]
  31. DATABASE_OPTIONS={}
  32. )
  33. Note: You will need to create the tables by hand if you use this option.
  34. """
  35. assert(not getattr(settings, 'DBLOG_DATABASE', None) or django.VERSION < (1, 2), 'The `DBLOG_DATABASE` setting requires Django < 1.2')
  36. class DBLogManager(models.Manager):
  37. def get_query_set(self):
  38. db_options = getattr(settings, 'DBLOG_DATABASE', None)
  39. if not db_options:
  40. return super(DBLogManager, self).get_query_set()
  41. connection = self.get_db_wrapper(db_options)
  42. if connection.features.uses_custom_query_class:
  43. Query = connection.ops.query_class(BaseQuery)
  44. else:
  45. Query = BaseQuery
  46. return QuerySet(self.model, Query(self.model, connection))
  47. def get_db_wrapper(self, options):
  48. backend = __import__('django.db.backends.' + options.get('DATABASE_ENGINE', settings.DATABASE_ENGINE)
  49. + ".base", {}, {}, ['base'])
  50. if django_is_10:
  51. backup = {}
  52. for key, value in options.iteritems():
  53. backup[key] = getattr(settings, key)
  54. setattr(settings, key, value)
  55. connection = backend.DatabaseWrapper(options)
  56. # if django_is_10:
  57. # connection._cursor(settings)
  58. # else:
  59. # wrapper._cursor()
  60. if django_is_10:
  61. for key, value in backup.iteritems():
  62. setattr(settings, key, value)
  63. return connection
  64. def _insert(self, values, return_id=False, raw_values=False):
  65. db_options = getattr(settings, 'DBLOG_DATABASE', None)
  66. if not db_options:
  67. return super(DBLogManager, self)._insert(values, return_id, raw_values)
  68. query = sql.InsertQuery(self.model, self.get_db_wrapper())
  69. query.insert_values(values, raw_values)
  70. ret = query.execute_sql(return_id)
  71. # XXX: Why is the following needed?
  72. query.connection._commit()
  73. thread_ident = thread.get_ident()
  74. if thread_ident in savepoint_state:
  75. del savepoint_state[thread_ident]
  76. return ret
  77. def create_from_exception(self, exception, url=None):
  78. from models import Error, ErrorBatch
  79. server_name = socket.gethostname()
  80. tb_text = traceback.format_exc()
  81. class_name = exception.__class__.__name__
  82. checksum = md5_constructor(tb_text).hexdigest()
  83. defaults = dict(
  84. class_name = class_name,
  85. message = smart_unicode(exception),
  86. url = url,
  87. server_name = server_name,
  88. traceback = tb_text,
  89. )
  90. try:
  91. instance = Error.objects.create(**defaults)
  92. batch, created = ErrorBatch.objects.get_or_create(
  93. class_name = class_name,
  94. server_name = server_name,
  95. checksum = checksum,
  96. defaults = defaults
  97. )
  98. if not created:
  99. batch.times_seen += 1
  100. batch.resolved = False
  101. batch.last_seen = datetime.datetime.now()
  102. batch.save()
  103. except Exception, exc:
  104. warnings.warn(smart_unicode(exc))
  105. return instance