Logging system to spy on users.
Project description
Data Logging
- Version:
1.2.3
Data Logging - логгер действий пользователя в системе. Отслеживаются такие события, как вход, выход пользователя, открытие окон, удаление, редактирование, создание записей в БД.
Зависимости
M3 >= 1.0
Django >= 1.3
Django JSON Field
South
Настройки
В settings.DATABASE_ROUTERS необходимо добавить datalogging.dbrouters.DataLoggerRouter. Если используется отдельная БД так же необходимо добавить datalogging.dbrouters.NotUseDataLoggerDBRouter.
В settings.MIDDLEWARE_CLASSES необходимо добавить datalogging.middleware.CaptureRequestMiddleware и datalogging.middleware.RequestTokenMiddleware.
- DATALOGGER_EVENT_TYPE
Разделение событий по типу (системные, юридически важные и т.д.). В дальнейшем, к перечислению можно обратиться через EventType.
Пример:
DATALOGGER_EVENT_TYPE = { 'SYSTEM': ('se', u'Системное событие'), }
- DATALOGGER_EVENT_CODE
Коды событий, изначально имеются 6 событий: insert, update, delete, login, logout, win_open. В дальнейшем, к перечислению можно обратиться через EventCode.
Пример:
DATALOGGER_EVENT_CODE = { 'CUSTOM_EVENT_CODE': ('cec', 'Собственный код события'), }
- DATALOGGER_SYSTEMS_ENUM
Перечисление подсистем, в которых возникает событие: В дальнейшем, к перечислению можно обратиться через SystemEnum.
Пример:
DATALOGGER_SYSTEMS_ENUM = { 'APPICATION': ('app', u'Основное приложение'), }
- DATALOGGER_SUSPECTS_MODEL
Список моделей, состояние которых необходимо отслеживать. Причем, в качестве элемента списка можно использовать как полный путь до модели, так и сокращенный. Как альтернатива, можно указывать DataLoggingManager прямо в классе модели.
Пример:
DATALOGGER_SUSPECTS_MODEL = [ 'module_name.ModelName', 'project_name.core.module_name.models.ModelName', ]
- DATALOGGER_EXCLUDE_ACTIONS
Перечисление имен классов паков или экшенов, которые не нужно логировать.
- DATALOGGER_EXCLUDE_FIELDS
Перечень полей, которые не надо использовать при сравнении состояний модели.
Пример:
DATALOGGER_EXCLUDE_FIELDS = [ 'version', 'begin', 'end', 'modified', ]
- DATALOGGER_DATABASE
Наименование БД из settings.DATABASES, которая будет использована в качестве бэкенда для логгера.
В случае, если БД отлична от основной БД приложения, то необходимо включить в settings.DATABASE_ROUTERS классы NotUseDataLoggerDBRouter и DataLoggerRouter.
Для корректной работы с миграциями требуется подключить модуль datalogging.south_migration который перекрывает команду South - migrate.
Пример:
INSTALLED_APPS += ('datalogging.south_migration',) DATALOGGER_DATABASE = 'log_db' DATABASE_ROUTERS = ( 'datalogging.dbrouters.DataLoggerRouter', 'datalogging.dbrouters.NotUseDataLoggerDBRouter', )
- DATALOGGER_SHUTUP
Если необходимо отключить логгер, то значение должно быть True в ином случае False.
- DATALOGGER_FORGET_SYS_EVENTS
Если необходимо отключить логирование системных событий, то значение должно быть True в ином случае False.
- DATALOGGER_HOOKED_ACTIONS
Для возможности кастомного логирования вызова определенных экшенов, требуется указать их в словаре вида:
DATALOGGER_EVENT_CODE = { 'CUSTOM_EVENT_CODE': ('cec', 'description event') } DATALOGGER_HOOKED_ACTIONS = { 'SomeActionClassName': 'CUSTOM_EVENT_CODE' }
Позже, событие с экшеном можно перехватить по коду в обработчике сигнала post_system_event_signal, в kwargs будут присутствовать action и request.
Использование
Добавить в INSTALLED_APPS.
Для использования логгера строго необходимо определить обработчики сигналов.
Сигналы
- msg_for_log_signal
Сигнал возникает при формировании логгером человекпонятного описания события. В случае, если событие системное(открытие пользователем окошка), то model_instance будет иметь None в качестве значения. В качестве возвращаемого значения должна быть представлена строка.
Передаваемые аргументы:
log_record - экземпляр записи лога,
model_instance - экземпляр записи модели,
fields_dict - словарь полей экземпляра модели, где ключ - имя поля, а значение - значение поля в модели.
- log_context_signal
Если приложение запущено в режиме фоновой задачи (Celery и т.д.) или в режиме шела, то request будет None.
Контекст события должен являться словарем и содержать значения:
suid - ID пользователя в среде, в которой произошло событие,
system_type - значение из SystemEnum описывающее текущую среду,
event_type - значение из EventType описывающее текущий тип события.
В качестве возвращаемого значения должен быть представлен словарь.
Передаваемые аргументы:
request - текущий запрос.
- post_snapshot_signal
Вызывается в момент формирования записи об измененном состоянии отслеживаемой модели. Позволяет изменить запись лога перед сохранением.
Передаваемые аргументы:
log_record - не сохраненный в БД экземпляр записи лога
- post_system_event_signal
Вызывается в момент формирования записи о событии происшедшем в системе. Позволяет изменить запись лога перед сохранением.
Передаваемые аргументы:
log_record - не сохраненный в БД экземпляр записи лога
Выборка записей
- filter_events
Позволяет отфильтровать записи лога. По поведению функция схожа с методом filter в Django ORM, с той лишь разницей, что есть возможность осуществлять поиск по сериализованным в JSON данным.
Пример (поиск по загловку окна):
filter_events( event_code=EventCode.WIN_OPEN, _context__title=u'Заголовок или его часть')
- get_events_by_token
Позволяет получить все записи с одинаковым токеном запроса. Т.е. все события возникшие в рамках одного запроса.
Пример:
get_events_by_token(some_log_record.request_token)
Пример
settings.py
... DATALOGGER_DATABASE = 'default' DATALOGGER_EXCLUDE_FIELDS = ('version', 'modified') DATALOGGER_EVENT_CODE = { 'CRITICAL_CHANGE': ('cc', u'Критичное изменение'), } DATALOGGER_SYSTEMS_ENUM = { 'APPLICATION': ('app', u'Основное приложение'), 'SCHEDULER': ('sch', u'Задачи вызыванные планировщиком'), } DATALOGGER_EVENT_TYPE = { 'SYSTEM_EVENT': ('se', u'Системное событие'), 'LEGALLY_EVENT': ('le', u'Юридически важное событие'), }
signals.py
from datalogging.signals import custom_verbose, custom_log_context, post_snapshot def verbose_handler(sender, log_record, model_instance, fields_dict): model_mapping = { 'module.Declaration': u'заявку (ID=%(id)s)', 'module.DeclarationUnit': u'привязку заявки (ID=%(declaration_id)s) к учреждению (ID=%(unit_id)s)', 'module.Children': u'ребенка (ID=%(id)s)', 'module.Pupil': u'запись о зачислении ребенка (ID=%(children_id)s в группу (ID=%(grup_id)s)', 'module.Deduct': u'запись об отчислении ребенка (ID=%(children_id)s) из группы (ID=%(group_id)s)', 'module.Group': u'группу (ID=%(id)s) учреждения (ID=%(unit_id)s)', 'module.Direct': u'направление заявки %(declaration_id)s в группу %(group_id)s' } operation_mapping = { EventCode.UPDATE: u'изменил(а)', EventCode.INSERT: u'создал(а)', EventCode.DELETE: u'удалил(а)' } if log_record.event_code == EventCode.WIN_OPEN: return u'Открыто окно: %s' % log_record.context_data['title'] what = u'запись в "%s"' % model_instance._meta.verbose_name if log_record.object_type in model_mapping: what = model_mapping[log_rec.object_type] % fields_dict verbose = u'Пользователь (ID=%s) %s %s.' % ( log_record.suid, operation_mapping.get(log_rec.event_code), what ) return verbose def context_handler(sender, request): if request is None: user_id = None system_type = SystemsEnum.SHELL event_type = EventType.UNDEFINED else: user_id = getattr(request.user, 'id', None) url = request.get_full_path() if '/some_pattern' in url: event_type = EventType.SOME_TYPE system_type = SystemsEnum.APPLICATION elif '/some_diffierent_pattern' in url: event_type = EventType.SOME_DIFFERENT_TYPE system_type = SystemType.SCHEDULER return {'suid': user_id, 'event_type': event_type, 'system_type': system_type} def post_snapshot_handler(sender, log_record): if log_record.object_type == 'module.SomeModelName' and log_record.event_code = EventCode.UPDATE: log_record.event_code = EventCode.CRITICAL_CHANGE msg_for_log_signal.connect(verbose_handler, weak=False) log_context_signal.connect(context_handler, weak=False) post_snapshot_signal.connect(post_snapshot_handler, weak=False)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.