mirror of
https://github.com/jazzband/django-ddp.git
synced 2026-03-16 22:40:24 +00:00
Pass all attributes from logging.LogRecord via dddp.logs collection.
This commit is contained in:
parent
f15efc0930
commit
05e3356b93
3 changed files with 49 additions and 59 deletions
|
|
@ -1,10 +1,12 @@
|
|||
from dddp import THREAD_LOCAL as this
|
||||
from dddp.api import API, Publication
|
||||
from dddp.logging import LOGS_NAME
|
||||
from django.contrib import auth
|
||||
|
||||
|
||||
class Logs(Publication):
|
||||
|
||||
name = LOGS_NAME
|
||||
users = auth.get_user_model()
|
||||
|
||||
def get_queries(self):
|
||||
|
|
|
|||
|
|
@ -3,31 +3,65 @@ from __future__ import absolute_import, print_function
|
|||
|
||||
import datetime
|
||||
import logging
|
||||
import traceback
|
||||
|
||||
from dddp import THREAD_LOCAL as this, meteor_random_id, ADDED
|
||||
|
||||
|
||||
LOGS_NAME = 'dddp.logs'
|
||||
|
||||
|
||||
def stacklines_or_none(exc_info):
|
||||
"""Return list of stack text lines or None."""
|
||||
if exc_info is None:
|
||||
return None
|
||||
return traceback.format_exception(*exc_info)
|
||||
|
||||
|
||||
class DDPHandler(logging.Handler):
|
||||
|
||||
"""Logging handler that streams log events via DDP to the current client."""
|
||||
|
||||
formatter = logging.BASIC_FORMAT
|
||||
|
||||
def emit(self, record):
|
||||
"""Emit a formatted log record via DDP."""
|
||||
if getattr(this, 'subs', {}).get('Logs', False):
|
||||
if getattr(this, 'subs', {}).get(LOGS_NAME, False):
|
||||
self.format(record)
|
||||
this.send({
|
||||
'msg': ADDED,
|
||||
'collection': 'logs',
|
||||
'id': meteor_random_id('/collection/logs'),
|
||||
'collection': LOGS_NAME,
|
||||
'id': meteor_random_id('/collection/%s' % LOGS_NAME),
|
||||
'fields': {
|
||||
'created': datetime.datetime.fromtimestamp(record.created),
|
||||
'name': record.name,
|
||||
'levelno': record.levelno,
|
||||
'levelname': record.levelname,
|
||||
# 'pathname': record.pathname,
|
||||
# 'lineno': record.lineno,
|
||||
'msg': record.msg,
|
||||
'args': record.args,
|
||||
# 'exc_info': record.exc_info,
|
||||
# 'funcName': record.funcName,
|
||||
attr: {
|
||||
# typecasting methods for specific attributes
|
||||
'args': lambda args: [repr(arg) for arg in args],
|
||||
'created': datetime.datetime.fromtimestamp,
|
||||
'exc_info': stacklines_or_none,
|
||||
}.get(
|
||||
attr,
|
||||
lambda val: val # default typecasting method
|
||||
)(getattr(record, attr, None))
|
||||
for attr in (
|
||||
'args',
|
||||
'asctime',
|
||||
'created',
|
||||
'exc_info',
|
||||
'filename',
|
||||
'funcName',
|
||||
'levelname',
|
||||
'levelno',
|
||||
'lineno',
|
||||
'module',
|
||||
'msecs',
|
||||
'message',
|
||||
'name',
|
||||
'pathname',
|
||||
'process',
|
||||
'processName',
|
||||
'relativeCreated',
|
||||
'thread',
|
||||
'threadName',
|
||||
)
|
||||
},
|
||||
})
|
||||
|
|
|
|||
46
dddp/msg.py
46
dddp/msg.py
|
|
@ -1,46 +0,0 @@
|
|||
"""Django DDP utils for DDP messaging."""
|
||||
from copy import deepcopy
|
||||
from dddp import THREAD_LOCAL as this, REMOVED
|
||||
try:
|
||||
from django.db.models.expressions import ExpressionNode
|
||||
except AttributeError:
|
||||
ExpressionNode = None
|
||||
|
||||
|
||||
def obj_change_as_msg(obj, msg):
|
||||
"""Generate a DDP msg for obj with specified msg type."""
|
||||
if ExpressionNode is None:
|
||||
exps = False
|
||||
else:
|
||||
# check for F expressions
|
||||
exps = [
|
||||
name for name, val in vars(obj).items()
|
||||
if isinstance(val, ExpressionNode)
|
||||
]
|
||||
if exps:
|
||||
# clone and update obj with values but only for the expression fields
|
||||
obj = deepcopy(obj)
|
||||
# Django 1.8 makes obj._meta public --> pylint: disable=W0212
|
||||
for name, val in obj._meta.model.objects.values(*exps).get(pk=obj.pk):
|
||||
setattr(obj, name, val)
|
||||
|
||||
# run serialization now that all fields are "concrete" (not F expressions)
|
||||
serializer = this.serializer
|
||||
data = serializer.serialize([obj])[0]
|
||||
|
||||
# collection name is <app>.<model>
|
||||
name = data['model']
|
||||
|
||||
# cast ID as string
|
||||
if not isinstance(data['pk'], basestring):
|
||||
data['pk'] = '%d' % data['pk']
|
||||
|
||||
payload = {
|
||||
'msg': msg,
|
||||
'collection': name,
|
||||
'id': data['pk'],
|
||||
}
|
||||
if msg != REMOVED:
|
||||
payload['fields'] = data['fields']
|
||||
|
||||
return (name, payload)
|
||||
Loading…
Reference in a new issue