Skip to content

Commit

Permalink
feat: add logging app
Browse files Browse the repository at this point in the history
  • Loading branch information
b1rger committed Jan 26, 2024
1 parent 2605de5 commit 2abf42b
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 0 deletions.
9 changes: 9 additions & 0 deletions apis_core/logging/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.apps import AppConfig


class LoggingConfig(AppConfig):
default_auto_field = "django.db.models.AutoField"
name = "apis_core.logging"

def ready(self):
from . import signals
47 changes: 47 additions & 0 deletions apis_core/logging/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Generated by Django 4.2.9 on 2024-01-26 08:14

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

initial = True

dependencies = [
("contenttypes", "0002_remove_content_type_name"),
]

operations = [
migrations.CreateModel(
name="CustomLogEntry",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("user", models.CharField(editable=False, max_length=150)),
("action_time", models.DateTimeField(auto_now_add=True)),
("object_id", models.PositiveIntegerField(blank=True, null=True)),
("message", models.TextField(null=True)),
("metadata", models.JSONField(null=True)),
(
"content_type",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
to="contenttypes.contenttype",
),
),
],
options={
"ordering": ["-action_time"],
},
),
]
Empty file.
65 changes: 65 additions & 0 deletions apis_core/logging/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models


class CustomLogEntryManager(models.Manager):
def log_action(self, user, obj=None, message="", metadata={}):
username = "System action"
if user:
username = str(user)
entry = self.model.objects.create(user=username)
if obj:
content_type = ContentType.objects.get_for_model(obj)
entry.content_type = content_type
natural_key = f"{content_type.app_label}.{content_type.name}"
metadata["natural_key"] = natural_key
message += f" {natural_key}: {obj}"
metadata["pk"] = obj.pk
if hasattr(obj, "id"):
entry.object_id = obj.id
if message:
entry.message = message
if metadata:
entry.metadata = metadata
entry.save()

def add_something(self, user, obj):
message = f"{user} added"
metadata = {"type": "add"}
self.log_action(user, obj, message, metadata)

def delete_something(self, user, obj):
message = f"{user} deleted"
metadata = {"type": "del"}
self.log_action(user, obj, message, metadata)

def change_something(self, user, obj, update_fields=[]):
message = f"{user} changed"
metadata = {"type": "change", "update_fields": update_fields}
self.log_action(user, obj, message, metadata)


class CustomLogEntry(models.Model):
"""
A custom LogEntry model. Django has its own contrib.admin.LogEntry, but that
is primarily used for actions in the admin area. Using a custom LogEntry we
are more flexible.
"""

user = models.CharField(max_length=150, editable=False)
action_time = models.DateTimeField(auto_now_add=True, editable=False)

content_type = models.ForeignKey(
ContentType, on_delete=models.CASCADE, blank=True, null=True
)
object_id = models.PositiveIntegerField(blank=True, null=True)
content_object = GenericForeignKey("content_type", "object_id")

message = models.TextField(null=True)
metadata = models.JSONField(null=True)

objects = CustomLogEntryManager()

class Meta:
ordering = ["-action_time"]
32 changes: 32 additions & 0 deletions apis_core/logging/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from crum import get_current_request

from .models import CustomLogEntry


@receiver(post_save)
def log_save(sender, instance, created, raw, using, update_fields, **kwargs):
if sender is CustomLogEntry:
return
user = None
request = get_current_request()
if request:
user = request.user
if created:
CustomLogEntry.objects.add_something(user, instance)
else:
if update_fields:
update_fields = list(update_fields)
CustomLogEntry.objects.change_something(user, instance, update_fields)


@receiver(post_delete)
def log_delete(sender, instance, using, origin, **kwargs):
if sender is CustomLogEntry:
return
user = None
request = get_current_request()
if request:
user = request.user
CustomLogEntry.objects.delete_something(user, instance)

0 comments on commit 2abf42b

Please sign in to comment.