Add `LoggedCommand` to JobLogs in django admin interface
This commit is contained in:
parent
6badbc480c
commit
5790fac78f
|
|
@ -2,9 +2,29 @@ from django.contrib import admin
|
|||
from django.contrib.auth import admin as auth_admin, get_user_model
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from vbv_lernwelt.core.models import JobLog
|
||||
from vbv_lernwelt.core.utils import pretty_print_json
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class LogAdmin(admin.ModelAdmin):
|
||||
def has_add_permission(self, request):
|
||||
return False
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
return False
|
||||
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
# set all fields read only
|
||||
return [field.name for field in self.opts.local_fields] + [
|
||||
field.name for field in self.opts.local_many_to_many
|
||||
]
|
||||
|
||||
def pretty_print_json(self, json_string):
|
||||
return pretty_print_json(json_string)
|
||||
|
||||
|
||||
@admin.register(User)
|
||||
class UserAdmin(auth_admin.UserAdmin):
|
||||
fieldsets = (
|
||||
|
|
@ -34,3 +54,27 @@ class UserAdmin(auth_admin.UserAdmin):
|
|||
"sso_id",
|
||||
]
|
||||
search_fields = ["first_name", "last_name", "email", "username", "sso_id"]
|
||||
|
||||
|
||||
@admin.register(JobLog)
|
||||
class JobLogAdmin(LogAdmin):
|
||||
date_hierarchy = "started"
|
||||
list_display = (
|
||||
"job_name",
|
||||
"started",
|
||||
"ended",
|
||||
"runtime",
|
||||
"success",
|
||||
)
|
||||
list_filter = ["job_name", "success"]
|
||||
|
||||
def json_data_pretty(self, instance):
|
||||
return self.pretty_print_json(instance.json_data)
|
||||
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
return super().get_readonly_fields(request, obj) + ["json_data_pretty"]
|
||||
|
||||
def runtime(self, obj):
|
||||
if obj.ended:
|
||||
return (obj.ended - obj.started).seconds // 60
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
import sys
|
||||
import traceback
|
||||
|
||||
import structlog
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils import timezone
|
||||
|
||||
from vbv_lernwelt.core.models import JobLog
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
|
||||
# pylint: disable=abstract-method
|
||||
class LoggedCommand(BaseCommand):
|
||||
def execute(self, *args, **options):
|
||||
name = getattr(self, "name", "")
|
||||
if not name:
|
||||
name = sys.argv[1]
|
||||
|
||||
logger.info("start LoggedCommand", job_name=name, label="job_log")
|
||||
|
||||
self.job_log = JobLog.objects.create(job_name=name)
|
||||
try:
|
||||
super(LoggedCommand, self).execute(*args, **options)
|
||||
self.job_log.refresh_from_db()
|
||||
self.job_log.ended = timezone.now()
|
||||
self.job_log.success = True
|
||||
self.job_log.save()
|
||||
logger.info(
|
||||
"LoggedCommand successfully ended", job_name=name, label="job_log"
|
||||
)
|
||||
except Exception as e:
|
||||
self.job_log.refresh_from_db()
|
||||
self.job_log.error_message = str(e)
|
||||
self.job_log.stack_trace = traceback.format_exc()
|
||||
self.job_log.save()
|
||||
logger.error("LoggedCommand failed", job_name=name, label="job_log")
|
||||
raise e
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
# Generated by Django 3.2.20 on 2023-08-25 15:23
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("core", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="JobLog",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("started", models.DateTimeField(auto_now_add=True)),
|
||||
("ended", models.DateTimeField(blank=True, null=True)),
|
||||
("job_name", models.CharField(max_length=255)),
|
||||
("success", models.BooleanField(default=False)),
|
||||
("error_message", models.TextField(blank=True, default="")),
|
||||
("stack_trace", models.TextField(blank=True, default="")),
|
||||
("json_data", models.JSONField(default=dict)),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
|
@ -41,3 +41,16 @@ class SecurityRequestResponseLog(models.Model):
|
|||
response_status_code = models.CharField(max_length=255, blank=True, default="")
|
||||
|
||||
additional_json_data = JSONField(default=dict, blank=True)
|
||||
|
||||
|
||||
class JobLog(models.Model):
|
||||
started = models.DateTimeField(auto_now_add=True)
|
||||
ended = models.DateTimeField(blank=True, null=True)
|
||||
job_name = models.CharField(max_length=255)
|
||||
success = models.BooleanField(default=False)
|
||||
error_message = models.TextField(blank=True, default="")
|
||||
stack_trace = models.TextField(blank=True, default="")
|
||||
json_data = models.JSONField(default=dict)
|
||||
|
||||
def __str__(self):
|
||||
return "{job_name} {started:%H:%M %d.%m.%Y}".format(**self.__dict__)
|
||||
|
|
|
|||
|
|
@ -38,3 +38,16 @@ def replace_whitespace(text, replacement=" "):
|
|||
|
||||
def get_django_content_type(obj):
|
||||
return obj._meta.app_label + "." + type(obj).__name__
|
||||
|
||||
|
||||
def pretty_print_json(json_string):
|
||||
try:
|
||||
parsed = json_string
|
||||
if isinstance(json_string, str):
|
||||
parsed = json.loads(json_string)
|
||||
return mark_safe(
|
||||
"<pre>{}</pre>".format(json.dumps(parsed, indent=4, sort_keys=True))
|
||||
)
|
||||
# pylint: disable=broad-except
|
||||
except Exception:
|
||||
return json_string
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 3.2.20 on 2023-08-25 15:23
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("course_session", "0004_coursesessionedoniqtest"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name="coursesessionassignment",
|
||||
options={"ordering": ["course_session", "submission_deadline__start"]},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name="coursesessionattendancecourse",
|
||||
options={"ordering": ["course_session", "due_date__start"]},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name="coursesessionedoniqtest",
|
||||
options={"ordering": ["course_session", "deadline__start"]},
|
||||
),
|
||||
]
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
from datetime import timedelta
|
||||
|
||||
import djclick as click
|
||||
import structlog
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from vbv_lernwelt.core.base import LoggedCommand
|
||||
from vbv_lernwelt.core.models import User
|
||||
from vbv_lernwelt.course.models import CourseSessionUser
|
||||
from vbv_lernwelt.course_session.models import CourseSessionAttendanceCourse
|
||||
|
|
@ -55,6 +55,8 @@ def attendance_course_reminder_notification_job():
|
|||
logger.info("No attendance courses found")
|
||||
|
||||
|
||||
@click.command()
|
||||
def command():
|
||||
attendance_course_reminder_notification_job()
|
||||
class Command(LoggedCommand):
|
||||
help = "Sends attendance course reminder notifications to participants"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
attendance_course_reminder_notification_job()
|
||||
|
|
|
|||
Loading…
Reference in New Issue