Skip to content

Commit 738de71

Browse files
move helper
1 parent 0c39215 commit 738de71

3 files changed

Lines changed: 53 additions & 52 deletions

File tree

dojo/auditlog.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,65 @@
77
import contextlib
88
import logging
99
import sys
10+
from datetime import date, datetime, time
1011

1112
import pghistory
13+
from dateutil.relativedelta import relativedelta
1214
from django.conf import settings
1315
from django.core.management import call_command
1416
from django.db import models
17+
from django.utils import timezone
1518

1619
logger = logging.getLogger(__name__)
1720

1821

22+
def run_flush_auditlog(retention_period: int | None = None,
23+
batch_size: int | None = None,
24+
max_batches: int | None = None) -> tuple[int, int, bool]:
25+
"""
26+
Deletes audit log entries older than the configured retention period.
27+
28+
Returns a tuple of (deleted_total, batches_done, reached_limit).
29+
"""
30+
# Import inside to avoid model import issues at startup
31+
from auditlog.models import LogEntry # noqa: PLC0415
32+
33+
retention_period = retention_period if retention_period is not None else getattr(settings, "AUDITLOG_FLUSH_RETENTION_PERIOD", -1)
34+
if retention_period < 0:
35+
logger.info("Flushing auditlog is disabled")
36+
return 0, 0, False
37+
38+
logger.info("Running Cleanup Task for Logentries with %d Months retention", retention_period)
39+
retention_day = date.today() - relativedelta(months=retention_period)
40+
cutoff_dt = datetime.combine(retention_day, time.min, tzinfo=timezone.get_current_timezone())
41+
42+
batch_size = batch_size if batch_size is not None else getattr(settings, "AUDITLOG_FLUSH_BATCH_SIZE", 1000)
43+
max_batches = max_batches if max_batches is not None else getattr(settings, "AUDITLOG_FLUSH_MAX_BATCHES", 100)
44+
45+
deleted_total = 0
46+
batches_done = 0
47+
while batches_done < max_batches:
48+
batch_qs = LogEntry.objects.filter(timestamp__lt=cutoff_dt).order_by("pk")
49+
pks = list(batch_qs.values_list("pk", flat=True)[:batch_size])
50+
if not pks:
51+
if batches_done == 0:
52+
logger.info("No outdated Logentries found")
53+
break
54+
qs = LogEntry.objects.filter(pk__in=pks)
55+
deleted_count = qs._raw_delete(qs.db)
56+
deleted_total += int(deleted_count)
57+
batches_done += 1
58+
logger.info("Deleted batch %s (size ~%s), total deleted: %s", batches_done, batch_size, deleted_total)
59+
60+
reached_limit = batches_done >= max_batches
61+
if reached_limit:
62+
logger.info("Reached max batches limit (%s). Remaining audit log entries will be deleted in the next run.", max_batches)
63+
else:
64+
logger.info("Total number of audit log entries deleted: %s", deleted_total)
65+
66+
return deleted_total, batches_done, reached_limit
67+
68+
1969
def enable_django_auditlog():
2070
"""Enable django-auditlog by registering models."""
2171
# Import inside function to avoid AppRegistryNotReady errors

dojo/management/commands/flush_auditlog.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from django.core.management.base import BaseCommand
22

3-
from dojo.tasks import run_flush_auditlog
3+
from dojo.auditlog import run_flush_auditlog
44

55

66
class Command(BaseCommand):

dojo/tasks.py

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
import logging
2-
from datetime import date, datetime, time, timedelta
2+
from datetime import timedelta
33

4-
from auditlog.models import LogEntry
54
from celery.utils.log import get_task_logger
6-
from dateutil.relativedelta import relativedelta
75
from django.apps import apps
86
from django.conf import settings
97
from django.core.management import call_command
108
from django.db.models import Count, Prefetch
119
from django.urls import reverse
1210
from django.utils import timezone
1311

12+
from dojo.auditlog import run_flush_auditlog
1413
from dojo.celery import app
1514
from dojo.decorators import dojo_async_task
1615
from dojo.finding.helper import fix_loop_duplicates
@@ -93,54 +92,6 @@ def cleanup_alerts(*args, **kwargs):
9392
logger.info("total number of alerts deleted: %s", total_deleted_count)
9493

9594

96-
def run_flush_auditlog(retention_period: int | None = None,
97-
batch_size: int | None = None,
98-
max_batches: int | None = None) -> tuple[int, int, bool]:
99-
"""
100-
Deletes audit log entries older than the configured retention period.
101-
102-
Returns a tuple of (deleted_total, batches_done, reached_limit).
103-
"""
104-
retention_period = retention_period if retention_period is not None else getattr(settings, "AUDITLOG_FLUSH_RETENTION_PERIOD", -1)
105-
if retention_period < 0:
106-
logger.info("Flushing auditlog is disabled")
107-
return 0, 0, False
108-
109-
logger.info("Running Cleanup Task for Logentries with %d Months retention", retention_period)
110-
# Compute a datetime cutoff at start of the cutoff day to keep index-usage friendly
111-
retention_day = date.today() - relativedelta(months=retention_period)
112-
# Use a timestamp to avoid postgres having to cast to a Date field
113-
cutoff_dt = datetime.combine(retention_day, time.min, tzinfo=timezone.get_current_timezone())
114-
115-
# Settings to control batching; sensible defaults if not configured
116-
batch_size = batch_size if batch_size is not None else getattr(settings, "AUDITLOG_FLUSH_BATCH_SIZE", 1000)
117-
max_batches = max_batches if max_batches is not None else getattr(settings, "AUDITLOG_FLUSH_MAX_BATCHES", 100)
118-
119-
# Delete in batches to avoid long-running transactions and table locks
120-
deleted_total = 0
121-
batches_done = 0
122-
while batches_done < max_batches:
123-
batch_qs = LogEntry.objects.filter(timestamp__lt=cutoff_dt).order_by("pk")
124-
pks = list(batch_qs.values_list("pk", flat=True)[:batch_size])
125-
if not pks:
126-
if batches_done == 0:
127-
logger.info("No outdated Logentries found")
128-
break
129-
qs = LogEntry.objects.filter(pk__in=pks)
130-
deleted_count = qs._raw_delete(qs.db)
131-
deleted_total += int(deleted_count)
132-
batches_done += 1
133-
logger.info("Deleted batch %s (size ~%s), total deleted: %s", batches_done, batch_size, deleted_total)
134-
135-
reached_limit = batches_done >= max_batches
136-
if reached_limit:
137-
logger.info("Reached max batches limit (%s). Remaining audit log entries will be deleted in the next run.", max_batches)
138-
else:
139-
logger.info("Total number of audit log entries deleted: %s", deleted_total)
140-
141-
return deleted_total, batches_done, reached_limit
142-
143-
14495
@app.task(bind=True)
14596
def flush_auditlog(*args, **kwargs):
14697
run_flush_auditlog()

0 commit comments

Comments
 (0)