mirror of
https://github.com/jlengrand/bugsink.git
synced 2026-03-10 08:01:17 +00:00
MAX_RETENTION[_PER_PROJECT] as a setting
This commit is contained in:
@@ -67,6 +67,9 @@ DEFAULTS = {
|
|||||||
|
|
||||||
"MAX_EMAILS_PER_MONTH": None, # None means "no limit"; for non-None values, the quota is per calendar month
|
"MAX_EMAILS_PER_MONTH": None, # None means "no limit"; for non-None values, the quota is per calendar month
|
||||||
|
|
||||||
|
"MAX_RETENTION_PER_PROJECT_EVENT_COUNT": None, # None means "no limit"
|
||||||
|
"MAX_RETENTION_EVENT_COUNT": None, # None means "no limit"
|
||||||
|
|
||||||
# I don't think Sentry specifies this one, but we do: given the spec 8KiB should be enough by an order of magnitude.
|
# I don't think Sentry specifies this one, but we do: given the spec 8KiB should be enough by an order of magnitude.
|
||||||
"MAX_HEADER_SIZE": 8 * _KIBIBYTE,
|
"MAX_HEADER_SIZE": 8 * _KIBIBYTE,
|
||||||
|
|
||||||
|
|||||||
@@ -173,6 +173,9 @@ BUGSINK = {
|
|||||||
"MAX_EVENTS_PER_HOUR": int(os.getenv("MAX_EVENTS_PER_HOUR", 5_000)),
|
"MAX_EVENTS_PER_HOUR": int(os.getenv("MAX_EVENTS_PER_HOUR", 5_000)),
|
||||||
"MAX_EVENTS_PER_MONTH": int(os.getenv("MAX_EVENTS_PER_MONTH", 1_000_000)),
|
"MAX_EVENTS_PER_MONTH": int(os.getenv("MAX_EVENTS_PER_MONTH", 1_000_000)),
|
||||||
|
|
||||||
|
"MAX_RETENTION_PER_PROJECT_EVENT_COUNT": int_or_none(os.getenv("MAX_RETENTION_PER_PROJECT_EVENT_COUNT", None)),
|
||||||
|
"MAX_RETENTION_EVENT_COUNT": int_or_none(os.getenv("MAX_RETENTION_EVENT_COUNT"), None),
|
||||||
|
|
||||||
# Settings that help with debugging and development ("why isn't Bugsink doing what I expect?")
|
# Settings that help with debugging and development ("why isn't Bugsink doing what I expect?")
|
||||||
"VALIDATE_ON_DIGEST": os.getenv("VALIDATE_ON_DIGEST", "none").lower(), # other legal values are "warn" and "strict"
|
"VALIDATE_ON_DIGEST": os.getenv("VALIDATE_ON_DIGEST", "none").lower(), # other legal values are "warn" and "strict"
|
||||||
"KEEP_ENVELOPES": int(os.getenv("KEEP_ENVELOPES", 0)), # keep this many in the database; 0 means "don't keep"
|
"KEEP_ENVELOPES": int(os.getenv("KEEP_ENVELOPES", 0)), # keep this many in the database; 0 means "don't keep"
|
||||||
|
|||||||
@@ -53,6 +53,15 @@ def deduce_script_name(base_url):
|
|||||||
return path if path not in (None, "", "/") else None
|
return path if path not in (None, "", "/") else None
|
||||||
|
|
||||||
|
|
||||||
|
def int_or_none(value):
|
||||||
|
if value is None:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
return int(value)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def eat_your_own_dogfood(sentry_dsn, **kwargs):
|
def eat_your_own_dogfood(sentry_dsn, **kwargs):
|
||||||
"""
|
"""
|
||||||
Configures your Bugsink installation to send messages to some Bugsink-compatible installation.
|
Configures your Bugsink installation to send messages to some Bugsink-compatible installation.
|
||||||
|
|||||||
@@ -111,7 +111,10 @@ BUGSINK = {
|
|||||||
"MAX_EVENTS_PER_HOUR": 50_000_000,
|
"MAX_EVENTS_PER_HOUR": 50_000_000,
|
||||||
"MAX_EVENTS_PER_MONTH": 1_000_000_000,
|
"MAX_EVENTS_PER_MONTH": 1_000_000_000,
|
||||||
|
|
||||||
"MAX_EMAILS_PER_MONTH": 10, # for development: a thing to tune if you want to the the quota system
|
# for development: things to tune if you want to the the quota system
|
||||||
|
"MAX_RETENTION_PER_PROJECT_EVENT_COUNT": None,
|
||||||
|
"MAX_RETENTION_EVENT_COUNT": None,
|
||||||
|
"MAX_EMAILS_PER_MONTH": 10,
|
||||||
|
|
||||||
"KEEP_ARTIFACT_BUNDLES": True, # in development: useful to preserve sourcemap uploads
|
"KEEP_ARTIFACT_BUNDLES": True, # in development: useful to preserve sourcemap uploads
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ from django.contrib.auth import get_user_model
|
|||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
|
from django.db.models import Sum
|
||||||
|
|
||||||
from bugsink.utils import assert_
|
from bugsink.utils import assert_
|
||||||
|
from bugsink.app_settings import get_settings
|
||||||
from teams.models import TeamMembership
|
from teams.models import TeamMembership
|
||||||
from bsmain.utils import yesno
|
from bsmain.utils import yesno
|
||||||
|
|
||||||
@@ -128,3 +130,24 @@ class ProjectForm(forms.ModelForm):
|
|||||||
# how Django does this (but it requires JQuery)
|
# how Django does this (but it requires JQuery)
|
||||||
|
|
||||||
# "alert_on_new_issue", "alert_on_regression", "alert_on_unmute" later
|
# "alert_on_new_issue", "alert_on_regression", "alert_on_unmute" later
|
||||||
|
|
||||||
|
def clean_retention_max_event_count(self):
|
||||||
|
retention_max_event_count = self.cleaned_data['retention_max_event_count']
|
||||||
|
|
||||||
|
if get_settings().MAX_RETENTION_PER_PROJECT_EVENT_COUNT is not None:
|
||||||
|
if retention_max_event_count > get_settings().MAX_RETENTION_PER_PROJECT_EVENT_COUNT:
|
||||||
|
raise forms.ValidationError("The maximum allowed retention per project is %d events." %
|
||||||
|
get_settings().MAX_RETENTION_PER_PROJECT_EVENT_COUNT)
|
||||||
|
|
||||||
|
if get_settings().MAX_RETENTION_EVENT_COUNT is not None:
|
||||||
|
sum_of_others = Project.objects.exclude(pk=self.instance.pk).aggregate(
|
||||||
|
total=Sum('retention_max_event_count'))['total'] or 0
|
||||||
|
budget_left = get_settings().MAX_RETENTION_EVENT_COUNT - sum_of_others
|
||||||
|
|
||||||
|
if retention_max_event_count > budget_left:
|
||||||
|
raise forms.ValidationError("The maximum allowed retention for this project is %d events (based on the "
|
||||||
|
"installation-wide max of %d events)." % (
|
||||||
|
budget_left,
|
||||||
|
get_settings().MAX_RETENTION_EVENT_COUNT))
|
||||||
|
|
||||||
|
return retention_max_event_count
|
||||||
|
|||||||
Reference in New Issue
Block a user