Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions api/organisations/task_helpers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging
from datetime import timedelta

import structlog
from dateutil.relativedelta import relativedelta
from django.conf import settings
from django.core.mail import send_mail
Expand All @@ -21,7 +21,7 @@

from .constants import API_USAGE_ALERT_THRESHOLDS

logger = logging.getLogger(__name__)
logger = structlog.get_logger("api_usage")


def send_api_flags_blocked_notification(organisation: Organisation) -> None:
Expand Down Expand Up @@ -115,10 +115,9 @@ def handle_api_usage_notification_for_organisation(organisation: Organisation) -
billing_starts_at = subscription_cache.current_billing_term_starts_at

if billing_starts_at is None:
# Since the calling code is a list of many organisations
# log the error and return without raising an exception.
logger.error(
f"Paid organisation {organisation.id} is missing billing_starts_at datetime"
"notification.missing_billing_starts_at",
organisation__id=organisation.id,
)
return

Expand Down Expand Up @@ -151,6 +150,17 @@ def handle_api_usage_notification_for_organisation(organisation: Organisation) -

matched_threshold = threshold

logger.info(
"notification.evaluated",
organisation__id=organisation.id,
api_usage=api_usage,
allowed_api_calls=allowed_api_calls,
api_usage_percent=api_usage_percent,
period_starts_at=period_starts_at.isoformat(),
period_ends_at=now.isoformat(),
matched_threshold=matched_threshold,
)

# Didn't match even the lowest threshold, so no notification.
if matched_threshold is None:
return
Expand All @@ -163,6 +173,12 @@ def handle_api_usage_notification_for_organisation(organisation: Organisation) -
# Already sent the max notification level so don't resend.
return

logger.info(
"notification.sent",
organisation__id=organisation.id,
matched_threshold=matched_threshold,
)

_send_api_usage_notification(organisation, matched_threshold)


Expand Down
16 changes: 10 additions & 6 deletions api/tests/unit/organisations/test_unit_organisations_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from freezegun.api import FrozenDateTimeFactory
from pytest_django.fixtures import SettingsWrapper
from pytest_mock import MockerFixture
from pytest_structlog import StructuredLogCapture

from core.helpers import get_current_site_url
from organisations.chargebee.metadata import ChargebeeObjMetadata
Expand Down Expand Up @@ -290,7 +291,7 @@ def test_send_org_subscription_cancelled_alert__valid_organisation__sends_cancel

def test_handle_api_usage_notification_for_organisation__billing_starts_at_is_none__logs_warning(
organisation: Organisation,
caplog: pytest.LogCaptureFixture,
log: StructuredLogCapture,
mocker: MockerFixture,
) -> None:
# Given
Expand All @@ -313,14 +314,18 @@ def test_handle_api_usage_notification_for_organisation__billing_starts_at_is_no

# Then
api_usage_mock.assert_not_called()
assert caplog.messages == [
f"Paid organisation {organisation.id} is missing billing_starts_at datetime"
assert log.events == [
{
"level": "error",
"event": "notification.missing_billing_starts_at",
"organisation__id": organisation.id,
}
]


def test_handle_api_usage_notification_for_organisation__cancellation_date_is_set__skips_notification(
organisation: Organisation,
caplog: pytest.LogCaptureFixture,
log: StructuredLogCapture,
mocker: MockerFixture,
) -> None:
# Given
Expand All @@ -346,8 +351,7 @@ def test_handle_api_usage_notification_for_organisation__cancellation_date_is_se
# Then
assert OrganisationAPIUsageNotification.objects.count() == 0

# Check to ensure that error messages haven't been set.
assert caplog.messages == []
assert not any(e["level"] == "error" for e in log.events)


def test_handle_api_usage_notification_for_organisation__billing_starts_at_over_12_months_ago__uses_12_month_offset(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,35 @@

### `api_usage.notification.evaluated`

Logged at `info` from:
- `api/organisations/task_helpers.py:153`

Attributes:
- `allowed_api_calls`
- `api_usage`
- `api_usage_percent`
- `matched_threshold`
- `organisation.id`
- `period_ends_at`
- `period_starts_at`

### `api_usage.notification.missing_billing_starts_at`

Logged at `error` from:
- `api/organisations/task_helpers.py:118`

Attributes:
- `organisation.id`

### `api_usage.notification.sent`

Logged at `info` from:
- `api/organisations/task_helpers.py:176`

Attributes:
- `matched_threshold`
- `organisation.id`

### `app_analytics.no_analytics_database_configured`

Logged at `warning` from:
Expand Down
Loading