diff --git a/events/factories.py b/events/factories.py index 4112871..bf99882 100644 --- a/events/factories.py +++ b/events/factories.py @@ -22,8 +22,8 @@ def create_event(project=None, issue=None, timestamp=None, event_data=None): event_data = create_event_data() max_current = Event.objects.filter(project=project).aggregate( - Max("ingest_order"))["ingest_order__max"] - issue_ingest_order = max_current + 1 if max_current is not None else 1 + Max("digest_order"))["digest_order__max"] + issue_digest_order = max_current + 1 if max_current is not None else 1 return Event.objects.create( project=project, @@ -34,7 +34,7 @@ def create_event(project=None, issue=None, timestamp=None, event_data=None): has_exception=True, has_logentry=True, data=json.dumps(event_data), - ingest_order=issue_ingest_order, + digest_order=issue_digest_order, irrelevance_for_retention=0, ) diff --git a/events/migrations/0010_rename_ingest_order_event_digest_order_and_more.py b/events/migrations/0010_rename_ingest_order_event_digest_order_and_more.py new file mode 100644 index 0000000..46247a4 --- /dev/null +++ b/events/migrations/0010_rename_ingest_order_event_digest_order_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.13 on 2024-07-16 13:23 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('issues', '0004_rename_event_count_issue_digested_event_count'), + ('projects', '0004_project_quota_exceeded_until'), + ('events', '0009_event_events_even_issue_i_90497b_idx'), + ] + + operations = [ + migrations.RenameField( + model_name='event', + old_name='ingest_order', + new_name='digest_order', + ), + migrations.AlterUniqueTogether( + name='event', + unique_together={('project', 'event_id'), ('issue', 'digest_order')}, + ), + ] diff --git a/events/models.py b/events/models.py index d84d541..5f17772 100644 --- a/events/models.py +++ b/events/models.py @@ -147,7 +147,7 @@ class Event(models.Model): # 1-based, because this is for human consumption only, and using 0-based internally when we don't actually do # anything with this value other than showing it to humans is super-confusing. Sorry Dijkstra! - ingest_order = models.PositiveIntegerField(blank=False, null=False) + digest_order = models.PositiveIntegerField(blank=False, null=False) # irrelevance_for_retention is set on-ingest based on the number of available events for an issue; it is combined # with age-based-irrelevance to determine which events will be evicted when retention quota are met. @@ -157,7 +157,7 @@ class Event(models.Model): class Meta: unique_together = [ ("project", "event_id"), - ("issue", "ingest_order"), + ("issue", "digest_order"), ] indexes = [ models.Index(fields=["project", "never_evict", "server_side_timestamp", "irrelevance_for_retention"]), @@ -179,7 +179,7 @@ class Event(models.Model): return get_title_for_exception_type_and_value(self.calculated_type, self.calculated_value) @classmethod - def from_ingested(cls, event_metadata, ingest_order, stored_event_count, issue, parsed_data, denormalized_fields): + def from_ingested(cls, event_metadata, digest_order, stored_event_count, issue, parsed_data, denormalized_fields): # 'from_ingested' may be a bit of a misnomer... the full 'from_ingested' is done in 'digest_event' in the views. # below at least puts the parsed_data in the right place, and does some of the basic object set up (FKs to other # objects etc). @@ -215,7 +215,7 @@ class Event(models.Model): debug_info=event_metadata["debug_info"], - ingest_order=ingest_order, + digest_order=digest_order, irrelevance_for_retention=irrelevance_for_retention, **denormalized_fields, diff --git a/events/retention.py b/events/retention.py index 6189743..3cc9d4b 100644 --- a/events/retention.py +++ b/events/retention.py @@ -57,7 +57,7 @@ def nonzero_leading_bits(n): return len(s.rstrip('0')) -def get_random_irrelevance(event_count): +def get_random_irrelevance(stored_event_count): """ gets a fixed-at-creation irrelevance-score for an Event; the basic idea is: the more events you have for a certain issue, the less relevant any new event will be _on average_; but when you have many events you will on average still @@ -67,7 +67,7 @@ def get_random_irrelevance(event_count): if `cnt` "hovers" around a certain value (which is likely to happen when there's repeated eviction/fill-up). ×2 is simply to correct for random() (which returns .5 on average). """ - return nonzero_leading_bits(round(random() * event_count * 2)) + return nonzero_leading_bits(round(random() * stored_event_count * 2)) def should_evict(project, timestamp, stored_event_count): diff --git a/ingest/views.py b/ingest/views.py index bc42fd5..f06341d 100644 --- a/ingest/views.py +++ b/ingest/views.py @@ -150,15 +150,15 @@ class BaseIngestAPIView(View): if not Grouping.objects.filter(project_id=event_metadata["project_id"], grouping_key=grouping_key).exists(): # we don't have Project.issue_count here ('premature optimization') so we just do an aggregate instead. max_current = Issue.objects.filter(project_id=event_metadata["project_id"]).aggregate( - Max("ingest_order"))["ingest_order__max"] - issue_ingest_order = max_current + 1 if max_current is not None else 1 + Max("digest_order"))["digest_order__max"] + issue_digest_order = max_current + 1 if max_current is not None else 1 issue = Issue.objects.create( - ingest_order=issue_ingest_order, + digest_order=issue_digest_order, project_id=event_metadata["project_id"], first_seen=timestamp, last_seen=timestamp, - event_count=1, + digested_event_count=1, **denormalized_fields, ) # even though in our data-model a given grouping does not imply a single Issue (in fact, that's the whole @@ -179,7 +179,7 @@ class BaseIngestAPIView(View): # update the denormalized fields issue.last_seen = timestamp - issue.event_count += 1 + issue.digested_event_count += 1 # NOTE: possibly expensive. "in theory" we can just do some bookkeeping for a denormalized value, but that may # be hard to keep in-sync in practice. Let's check the actual cost first. @@ -200,7 +200,7 @@ class BaseIngestAPIView(View): # information available here, we could add it to the Event model. event, event_created = Event.from_ingested( event_metadata, - issue.event_count, + issue.digested_event_count, issue_stored_event_count, issue, event_data, diff --git a/issues/admin.py b/issues/admin.py index ab0b50e..40bf630 100644 --- a/issues/admin.py +++ b/issues/admin.py @@ -47,7 +47,7 @@ class IssueAdmin(admin.ModelAdmin): 'is_muted', 'unmute_on_volume_based_conditions', 'unmute_after', - 'event_count', + 'digested_event_count', ] inlines = [ @@ -58,7 +58,7 @@ class IssueAdmin(admin.ModelAdmin): list_display = [ "title", "project", - "event_count", + "digested_event_count", ] list_filter = [ "project", @@ -71,5 +71,5 @@ class IssueAdmin(admin.ModelAdmin): 'friendly_id', 'calculated_type', 'calculated_value', - 'event_count', + 'digested_event_count', ] diff --git a/issues/factories.py b/issues/factories.py index 9e1d031..2c25582 100644 --- a/issues/factories.py +++ b/issues/factories.py @@ -53,5 +53,5 @@ def denormalized_issue_fields(): return { "first_seen": timezone.now(), "last_seen": timezone.now(), - "event_count": 1, + "digested_event_count": 1, } diff --git a/issues/migrations/0004_rename_event_count_issue_digested_event_count.py b/issues/migrations/0004_rename_event_count_issue_digested_event_count.py new file mode 100644 index 0000000..7bbe22b --- /dev/null +++ b/issues/migrations/0004_rename_event_count_issue_digested_event_count.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.13 on 2024-07-16 13:18 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('issues', '0003_alter_turningpoint_triggering_event'), + ] + + operations = [ + migrations.RenameField( + model_name='issue', + old_name='event_count', + new_name='digested_event_count', + ), + ] diff --git a/issues/migrations/0005_rename_ingest_order_issue_digest_order_and_more.py b/issues/migrations/0005_rename_ingest_order_issue_digest_order_and_more.py new file mode 100644 index 0000000..e78bf29 --- /dev/null +++ b/issues/migrations/0005_rename_ingest_order_issue_digest_order_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.13 on 2024-07-16 13:23 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0004_project_quota_exceeded_until'), + ('issues', '0004_rename_event_count_issue_digested_event_count'), + ] + + operations = [ + migrations.RenameField( + model_name='issue', + old_name='ingest_order', + new_name='digest_order', + ), + migrations.AlterUniqueTogether( + name='issue', + unique_together={('project', 'digest_order')}, + ), + ] diff --git a/issues/models.py b/issues/models.py index d991461..b04f7ae 100644 --- a/issues/models.py +++ b/issues/models.py @@ -31,13 +31,13 @@ class Issue(models.Model): project = models.ForeignKey( "projects.Project", blank=False, null=True, on_delete=models.SET_NULL) # SET_NULL: cleanup 'later' - # 1-based for the same reasons as Event.ingest_order - ingest_order = models.PositiveIntegerField(blank=False, null=False) + # 1-based for the same reasons as Event.digest_order + digest_order = models.PositiveIntegerField(blank=False, null=False) # denormalized/cached fields: last_seen = models.DateTimeField(blank=False, null=False) # based on event.server_side_timestamp first_seen = models.DateTimeField(blank=False, null=False) # based on event.server_side_timestamp - event_count = models.IntegerField(blank=False, null=False) + digested_event_count = models.IntegerField(blank=False, null=False) calculated_type = models.CharField(max_length=255, blank=True, null=False, default="") calculated_value = models.CharField(max_length=255, blank=True, null=False, default="") transaction = models.CharField(max_length=200, blank=True, null=False, default="") @@ -60,15 +60,15 @@ class Issue(models.Model): unmute_after = models.DateTimeField(blank=True, null=True) def save(self, *args, **kwargs): - if self.ingest_order is None: + if self.digest_order is None: # testing-only; in production this should never happen and instead have been done in the ingest view. - max_current = self.ingest_order = Issue.objects.filter(project=self.project).aggregate( - models.Max("ingest_order"))["ingest_order__max"] - self.ingest_order = max_current + 1 if max_current is not None else 1 + max_current = self.digest_order = Issue.objects.filter(project=self.project).aggregate( + models.Max("digest_order"))["digest_order__max"] + self.digest_order = max_current + 1 if max_current is not None else 1 super().save(*args, **kwargs) def friendly_id(self): - return f"{ self.project.slug.upper() }-{ self.ingest_order }" + return f"{ self.project.slug.upper() }-{ self.digest_order }" def get_absolute_url(self): return f"/issues/issue/{ self.id }/event/last/" @@ -104,7 +104,7 @@ class Issue(models.Model): class Meta: unique_together = [ - ("project", "ingest_order"), + ("project", "digest_order"), ] indexes = [ models.Index(fields=["first_seen"]), diff --git a/issues/templates/issues/_event_nav.html b/issues/templates/issues/_event_nav.html index 57ab3f4..431cc7c 100644 --- a/issues/templates/issues/_event_nav.html +++ b/issues/templates/issues/_event_nav.html @@ -1,5 +1,5 @@ - {% if event.ingest_order > 1 %} - + {% if event.digest_order > 1 %} + {% else %} @@ -8,8 +8,8 @@ {% endif %} - {% if event.ingest_order < issue.event_count %} - + {% if event.digest_order < issue.digested_event_count %} + {% else %} diff --git a/issues/templates/issues/base.html b/issues/templates/issues/base.html index e60f798..79f5376 100644 --- a/issues/templates/issues/base.html +++ b/issues/templates/issues/base.html @@ -118,7 +118,7 @@