Skip to content

Commit

Permalink
Merge pull request #28 from maykinmedia/feature/cleanup-logs
Browse files Browse the repository at this point in the history
add task and management command for cleaning up logs
  • Loading branch information
sergei-maertens authored Oct 5, 2023
2 parents 272d3e9 + ef93d52 commit f24e9e5
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 0 deletions.
4 changes: 4 additions & 0 deletions docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ you likely want to apply the following non-default settings:
LOG_OUTGOING_REQUESTS_DB_SAVE = True # save logs enabled/disabled based on the boolean value
LOG_OUTGOING_REQUESTS_DB_SAVE_BODY = True # save request/response body
LOG_OUTGOING_REQUESTS_EMIT_BODY = True # log request/response body
LOG_OUTGOING_REQUESTS_MAX_AGE = 1 # delete requests older than 1 day
.. note::

Expand All @@ -100,6 +101,9 @@ you likely want to apply the following non-default settings:
(which defines if/when database logging is reset after changes to the library config) should
be set to ``None``.

The library provides a Django management command as well as a Celery task to delete
logs which are older than a specified time (by default, 1 day).

See :ref:`reference_settings` for all available settings and their meaning.

Usage
Expand Down
6 changes: 6 additions & 0 deletions log_outgoing_requests/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ class LogOutgoingRequestsConf(AppConf):
database, but the body will be missing.
"""

MAX_AGE = 1
"""
The maximum age (in days) of request logs, after which they are deleted (via a Celery
task, Django management command, or the like).
"""

RESET_DB_SAVE_AFTER = 60
"""
If the config has been updated, reset the database logging after the specified
Expand Down
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.core.management.base import BaseCommand

from ...models import OutgoingRequestsLog


class Command(BaseCommand):
def handle(self, *args, **kwargs):
num_deleted = OutgoingRequestsLog.objects.prune()
self.stdout.write(f"Deleted {num_deleted} outgoing request log(s)")
15 changes: 15 additions & 0 deletions log_outgoing_requests/models.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import logging
from datetime import timedelta
from typing import Union
from urllib.parse import urlparse

from django.core.validators import MinValueValidator
from django.db import models
from django.utils import timezone
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _

Expand All @@ -16,6 +18,17 @@
logger = logging.getLogger(__name__)


class OutgoingRequestsLogQueryset(models.QuerySet):
def prune(self) -> int:
max_age = settings.LOG_OUTGOING_REQUESTS_MAX_AGE
if max_age is None:
return 0

now = timezone.now()
num_deleted, _ = self.filter(timestamp__lt=now - timedelta(max_age)).delete()
return num_deleted


class OutgoingRequestsLog(models.Model):
url = models.URLField(
verbose_name=_("URL"),
Expand Down Expand Up @@ -108,6 +121,8 @@ class OutgoingRequestsLog(models.Model):
help_text=_("Text providing information in case of request failure."),
)

objects = OutgoingRequestsLogQueryset.as_manager()

class Meta:
verbose_name = _("Outgoing request log")
verbose_name_plural = _("Outgoing request logs")
Expand Down
13 changes: 13 additions & 0 deletions log_outgoing_requests/tasks.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
import logging

from .compat import shared_task
from .constants import SaveLogsChoice

logger = logging.getLogger(__name__)


@shared_task
def prune_logs():
from .models import OutgoingRequestsLog

num_deleted = OutgoingRequestsLog.objects.prune()
logger.info("Deleted %d outgoing request log(s)", num_deleted)
return num_deleted


@shared_task
def reset_config():
Expand Down
49 changes: 49 additions & 0 deletions tests/test_tasks.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import logging
from io import StringIO

from django.core.management import call_command
from django.utils import timezone

import pytest
import requests
from freezegun import freeze_time

from log_outgoing_requests.config_reset import schedule_config_reset
from log_outgoing_requests.models import OutgoingRequestsLog, OutgoingRequestsLogConfig
Expand All @@ -12,6 +19,48 @@
has_celery = celery is not None


@pytest.mark.django_db
def test_cleanup_request_logs_command(settings, caplog):
settings.LOG_OUTGOING_REQUESTS_MAX_AGE = 1 # delete if > 1 day old

with freeze_time("2023-10-02T12:00:00Z") as frozen_time:
OutgoingRequestsLog.objects.create(timestamp=timezone.now())
frozen_time.move_to("2023-10-04T12:00:00Z")
recent_log = OutgoingRequestsLog.objects.create(timestamp=timezone.now())

stdout = StringIO()
with caplog.at_level(logging.INFO):
call_command(
"prune_outgoing_request_logs", stdout=stdout, stderr=StringIO()
)

output = stdout.getvalue()
assert output == "Deleted 1 outgoing request log(s)\n"

assert OutgoingRequestsLog.objects.get() == recent_log


@pytest.mark.skipif(not has_celery, reason="Celery is optional dependency")
@pytest.mark.django_db
def test_cleanup_request_logs_celery_task(requests_mock, settings, caplog):
from log_outgoing_requests.tasks import prune_logs

settings.LOG_OUTGOING_REQUESTS_MAX_AGE = 1 # delete if > 1 old old

with freeze_time("2023-10-02T12:00:00Z") as frozen_time:
OutgoingRequestsLog.objects.create(timestamp=timezone.now())
frozen_time.move_to("2023-10-04T12:00:00Z")
recent_log = OutgoingRequestsLog.objects.create(timestamp=timezone.now())

with caplog.at_level(logging.INFO):
prune_logs()

assert len(caplog.records) == 1
assert "Deleted 1 outgoing request log(s)" in caplog.text

assert OutgoingRequestsLog.objects.get() == recent_log


@pytest.mark.skipif(not has_celery, reason="Celery is optional dependency")
@pytest.mark.django_db
def test_reset_config(requests_mock, settings):
Expand Down

0 comments on commit f24e9e5

Please sign in to comment.