mirror of
https://github.com/bugsink/bugsink.git
synced 2025-12-20 20:41:01 -06:00
ingest_order: first setup
This commit is contained in:
@@ -22,6 +22,7 @@ def create_event(project, issue, timestamp=None, event_data=None):
|
||||
has_exception=True,
|
||||
has_logentry=True,
|
||||
data=json.dumps(event_data),
|
||||
ingest_order=0,
|
||||
)
|
||||
|
||||
|
||||
|
||||
19
events/migrations/0013_event_ingest_order.py
Normal file
19
events/migrations/0013_event_ingest_order.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.11 on 2024-04-08 19:08
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0012_events_calculated_data'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='ingest_order',
|
||||
field=models.IntegerField(default=666),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
24
events/migrations/0014_fill_ingest_order.py
Normal file
24
events/migrations/0014_fill_ingest_order.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# Generated by Django 4.2.11 on 2024-04-08 19:22
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def fill_ingest_order(apps, schema_editor):
|
||||
Issue = apps.get_model('issues', 'Issue')
|
||||
Event = apps.get_model('events', 'Event')
|
||||
|
||||
for issue in Issue.objects.all():
|
||||
for i, event in enumerate(Event.objects.filter(issue=issue).order_by('server_side_timestamp', 'timestamp')):
|
||||
event.ingest_order = i + 1
|
||||
event.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('events', '0013_event_ingest_order'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(fill_ingest_order),
|
||||
]
|
||||
@@ -138,6 +138,10 @@ class Event(models.Model):
|
||||
calculated_type = models.CharField(max_length=255, blank=True, null=False, default="")
|
||||
calculated_value = models.CharField(max_length=255, blank=True, null=False, default="")
|
||||
|
||||
# 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.IntegerField(blank=False, null=False)
|
||||
|
||||
class Meta:
|
||||
unique_together = (("project", "event_id"),)
|
||||
# index_together = (("group_id", "datetime"),) TODO seriously think about indexes
|
||||
@@ -154,7 +158,7 @@ class Event(models.Model):
|
||||
return "/events/event/%s/download/" % self.id
|
||||
|
||||
@classmethod
|
||||
def from_ingested(cls, ingested_event, issue, parsed_data, calculated_type, calculated_value):
|
||||
def from_ingested(cls, ingested_event, ingest_order, issue, parsed_data, calculated_type, calculated_value):
|
||||
# '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).
|
||||
@@ -191,6 +195,7 @@ class Event(models.Model):
|
||||
|
||||
'calculated_type': calculated_type,
|
||||
'calculated_value': calculated_value,
|
||||
'ingest_order': ingest_order,
|
||||
}
|
||||
)
|
||||
return event, created
|
||||
|
||||
@@ -134,7 +134,15 @@ class BaseIngestAPIView(APIView):
|
||||
|
||||
# NOTE: an event always has a single (automatically calculated) Grouping associated with it. Since we have that
|
||||
# information available here, we could add it to the Event model.
|
||||
event, event_created = Event.from_ingested(ingested_event, issue, event_data, calculated_type, calculated_value)
|
||||
event, event_created = Event.from_ingested(
|
||||
ingested_event,
|
||||
# the assymetry with + 1 is because the event_count is only incremented below for the not issue_created case
|
||||
issue.event_count if issue_created else issue.event_count + 1,
|
||||
issue,
|
||||
event_data,
|
||||
calculated_type,
|
||||
calculated_value,
|
||||
)
|
||||
if not event_created:
|
||||
# note: previously we created the event before the issue, which allowed for one less query. I don't see
|
||||
# straight away how we can reproduce that now that we create issue-before-event (since creating the issue
|
||||
|
||||
19
issues/templates/issues/_event_nav.html
Normal file
19
issues/templates/issues/_event_nav.html
Normal file
@@ -0,0 +1,19 @@
|
||||
{% if event.ingest_order > 1 %}
|
||||
<a href="{% url this_view issue_pk=issue.pk ingest_order=event.ingest_order|add:"-1" %}" class="font-bold text-slate-500 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md hover:bg-slate-200 active:ring inline-flex items-center justify-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-6 h-6"><path fill-rule="evenodd" d="M9.78 4.22a.75.75 0 0 1 0 1.06L7.06 8l2.72 2.72a.75.75 0 1 1-1.06 1.06L5.47 8.53a.75.75 0 0 1 0-1.06l3.25-3.25a.75.75 0 0 1 1.06 0Z" clip-rule="evenodd" /></svg>
|
||||
</a>
|
||||
{% else %}
|
||||
<div class="font-bold text-slate-300 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md inline-flex items-center justify-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-6 h-6"><path fill-rule="evenodd" d="M9.78 4.22a.75.75 0 0 1 0 1.06L7.06 8l2.72 2.72a.75.75 0 1 1-1.06 1.06L5.47 8.53a.75.75 0 0 1 0-1.06l3.25-3.25a.75.75 0 0 1 1.06 0Z" clip-rule="evenodd" /></svg>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if event.ingest_order < issue.event_count %}
|
||||
<a href="{% url this_view issue_pk=issue.pk ingest_order=event.ingest_order|add:"1" %}"" class="font-bold text-slate-500 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md hover:bg-slate-200 active:ring inline-flex items-center justify-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-6 h-6"><path fill-rule="evenodd" d="M6.22 4.22a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06L8.94 8 6.22 5.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" /></svg>
|
||||
</a>
|
||||
{% else %}
|
||||
<div class="font-bold text-slate-300 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md inline-flex items-center justify-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-6 h-6"><path fill-rule="evenodd" d="M6.22 4.22a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06L8.94 8 6.22 5.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" /></svg>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -117,7 +117,7 @@
|
||||
</div>
|
||||
|
||||
<div class="flex p-4 bg-slate-200 border-b-2"><!-- bottom nav bar -->
|
||||
{% if is_event_page %}<div>Event ... {# TODO #} out of {{ issue.event_count}} which occured at <span class="font-bold">{{ event.server_side_timestamp|date:"j M G:i" }}</span></div>{% endif %}
|
||||
{% if is_event_page %}<div>Event {{ event.ingest_order }} of {{ issue.event_count}} which occured at <span class="font-bold">{{ event.server_side_timestamp|date:"j M G:i" }}</span></div>{% endif %}
|
||||
<div class="ml-auto pr-4 font-bold text-slate-500">
|
||||
<a href="/admin/issues/issue/{{ issue.id }}/change/">Issue Admin</a>
|
||||
{% if is_event_page %}
|
||||
|
||||
@@ -5,6 +5,18 @@
|
||||
|
||||
{% block tab_content %}
|
||||
|
||||
<div class="flex">
|
||||
<div class="overflow-hidden">
|
||||
<div class="italic">{{ event.server_side_timestamp|date:"j M G:i" }} (Event {{ event.ingest_order }} of {{ issue.event_count }})</div>
|
||||
</div>
|
||||
|
||||
<div class="ml-auto flex-none">
|
||||
<div class="flex place-content-end">
|
||||
{% include "issues/_event_nav.html" %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if not parsed_data.breadcrumbs or not parsed_data.breadcrumbs.values %}
|
||||
|
||||
<div class="mt-6 mb-6 italic">
|
||||
@@ -13,6 +25,7 @@
|
||||
|
||||
{% else %}
|
||||
|
||||
<div class="pt-4">
|
||||
<table class="w-full">
|
||||
{# <thead> </thead> #}
|
||||
<tbody>
|
||||
@@ -43,6 +56,7 @@
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -4,6 +4,19 @@
|
||||
|
||||
{% block tab_content %}
|
||||
|
||||
<div class="flex">
|
||||
<div class="overflow-hidden">
|
||||
<div class="italic">{{ event.server_side_timestamp|date:"j M G:i" }} (Event {{ event.ingest_order }} of {{ issue.event_count }})</div>
|
||||
</div>
|
||||
|
||||
<div class="ml-auto flex-none">
|
||||
<div class="flex place-content-end">
|
||||
{% include "issues/_event_nav.html" %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{# NOTE if we store event.grouper on the event, we could also show that here #}
|
||||
{% if not parsed_data.top_levels and not parsed_data.tags and not parsed_data.user and not parsed_data.request and not parsed_data.contexts.runtime and not parsed_data.modules and not parsed_data.sdk and not parsed_data.extra %}{# and not parsed_data.contexts.trace #}
|
||||
|
||||
|
||||
@@ -6,6 +6,19 @@
|
||||
{% block tab_content %}
|
||||
|
||||
{% if not exceptions %}
|
||||
{# event-nav only #}
|
||||
<div class="flex">
|
||||
<div class="overflow-hidden">
|
||||
<div class="italic">{{ event.server_side_timestamp|date:"j M G:i" }} (Event {{ event.ingest_order }} of {{ issue.event_count }})</div>
|
||||
</div>
|
||||
|
||||
<div class="ml-auto flex-none">
|
||||
<div class="flex place-content-end">
|
||||
{% include "issues/_event_nav.html" %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 mb-6 italic">
|
||||
No stacktrace available for this event.
|
||||
</div>
|
||||
@@ -16,6 +29,9 @@
|
||||
|
||||
<div class="flex">
|
||||
<div class="overflow-hidden">
|
||||
{% if forloop.counter0 == 0 %}
|
||||
<div class="italic">{{ event.server_side_timestamp|date:"j M G:i" }} (Event {{ event.ingest_order }} of {{ issue.event_count }})</div>
|
||||
{% endif %}
|
||||
<h1 class="text-2xl font-bold {% if forloop.counter0 > 0 %}mt-4{% endif %} text-ellipsis whitespace-nowrap overflow-hidden">{{ exception.type }}</h1>
|
||||
<div class="text-lg mb-4 text-ellipsis whitespace-nowrap overflow-hidden">{{ exception.value }}</div>
|
||||
|
||||
@@ -27,6 +43,8 @@
|
||||
<button class="font-bold text-slate-500 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md hover:bg-slate-200 active:ring" onclick="showInAppFrames()">Show in-app</button>
|
||||
<button class="font-bold text-slate-500 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md hover:bg-slate-200 active:ring" onclick="showRaisingFrame()">Show raise</button>
|
||||
<button class="font-bold text-slate-500 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md hover:bg-slate-200 active:ring" onclick="hideAllFrames()">Collapse all</button>
|
||||
|
||||
{% include "issues/_event_nav.html" %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -11,9 +11,15 @@ urlpatterns = [
|
||||
path('<int:project_pk>/muted/', issue_list, {"state_filter": "muted"}, name="issue_list_muted"),
|
||||
path('<int:project_pk>/all/', issue_list, {"state_filter": "all"}, name="issue_list_all"),
|
||||
|
||||
path('issue/<uuid:issue_pk>/event/<uuid:event_pk>/', issue_event_stacktrace),
|
||||
path('issue/<uuid:issue_pk>/event/<uuid:event_pk>/details/', issue_event_details),
|
||||
path('issue/<uuid:issue_pk>/event/<uuid:event_pk>/breadcrumbs/', issue_event_breadcrumbs),
|
||||
path('issue/<uuid:issue_pk>/event/<uuid:event_pk>/', issue_event_stacktrace, name="event_stacktrace"),
|
||||
path('issue/<uuid:issue_pk>/event/<uuid:event_pk>/details/', issue_event_details, name="event_details"),
|
||||
path('issue/<uuid:issue_pk>/event/<uuid:event_pk>/breadcrumbs/', issue_event_breadcrumbs, name="event_breadcrumbs"),
|
||||
|
||||
path('issue/<uuid:issue_pk>/event/<int:ingest_order>/', issue_event_stacktrace, name="event_stacktrace"),
|
||||
path('issue/<uuid:issue_pk>/event/<int:ingest_order>/details/', issue_event_details, name="event_details"),
|
||||
path('issue/<uuid:issue_pk>/event/<int:ingest_order>/breadcrumbs/', issue_event_breadcrumbs,
|
||||
name="event_breadcrumbs"),
|
||||
|
||||
path('issue/<uuid:issue_pk>/history/', issue_history),
|
||||
path('issue/<uuid:issue_pk>/grouping/', issue_grouping),
|
||||
path('issue/<uuid:issue_pk>/event/last/', issue_last_event),
|
||||
|
||||
@@ -163,12 +163,21 @@ def _handle_post(request, issue):
|
||||
return HttpResponseRedirect(request.path_info)
|
||||
|
||||
|
||||
def _get_event(issue, event_pk, ingest_order):
|
||||
if event_pk is not None:
|
||||
return get_object_or_404(Event, pk=event_pk)
|
||||
elif ingest_order is not None:
|
||||
return get_object_or_404(Event, issue=issue, ingest_order=ingest_order)
|
||||
else:
|
||||
raise ValueError("either event_pk or ingest_order must be provided")
|
||||
|
||||
|
||||
@issue_membership_required
|
||||
def issue_event_stacktrace(request, issue, event_pk):
|
||||
def issue_event_stacktrace(request, issue, event_pk=None, ingest_order=None):
|
||||
if request.method == "POST":
|
||||
return _handle_post(request, issue)
|
||||
|
||||
event = get_object_or_404(Event, pk=event_pk)
|
||||
event = _get_event(issue, event_pk, ingest_order)
|
||||
|
||||
parsed_data = json.loads(event.data)
|
||||
|
||||
@@ -207,6 +216,7 @@ def issue_event_stacktrace(request, issue, event_pk):
|
||||
|
||||
return render(request, "issues/issue_stacktrace.html", {
|
||||
"tab": "stacktrace",
|
||||
"this_view": "event_stacktrace",
|
||||
"project": issue.project,
|
||||
"issue": issue,
|
||||
"event": event,
|
||||
@@ -219,16 +229,17 @@ def issue_event_stacktrace(request, issue, event_pk):
|
||||
|
||||
|
||||
@issue_membership_required
|
||||
def issue_event_breadcrumbs(request, issue, event_pk):
|
||||
def issue_event_breadcrumbs(request, issue, event_pk=None, ingest_order=None):
|
||||
if request.method == "POST":
|
||||
return _handle_post(request, issue)
|
||||
|
||||
event = get_object_or_404(Event, pk=event_pk)
|
||||
event = _get_event(issue, event_pk, ingest_order)
|
||||
|
||||
parsed_data = json.loads(event.data)
|
||||
|
||||
return render(request, "issues/issue_breadcrumbs.html", {
|
||||
"tab": "breadcrumbs",
|
||||
"this_view": "event_breadcrumbs",
|
||||
"project": issue.project,
|
||||
"issue": issue,
|
||||
"event": event,
|
||||
@@ -239,11 +250,11 @@ def issue_event_breadcrumbs(request, issue, event_pk):
|
||||
|
||||
|
||||
@issue_membership_required
|
||||
def issue_event_details(request, issue, event_pk):
|
||||
def issue_event_details(request, issue, event_pk=None, ingest_order=None):
|
||||
if request.method == "POST":
|
||||
return _handle_post(request, issue)
|
||||
|
||||
event = get_object_or_404(Event, pk=event_pk)
|
||||
event = _get_event(issue, event_pk, ingest_order)
|
||||
parsed_data = json.loads(event.data)
|
||||
|
||||
parsed_data["top_levels"] = \
|
||||
@@ -253,6 +264,7 @@ def issue_event_details(request, issue, event_pk):
|
||||
|
||||
return render(request, "issues/issue_event_details.html", {
|
||||
"tab": "event-details",
|
||||
"this_view": "event_details",
|
||||
"project": issue.project,
|
||||
"issue": issue,
|
||||
"event": event,
|
||||
|
||||
29
theme/static/css/dist/styles.css
vendored
29
theme/static/css/dist/styles.css
vendored
@@ -898,6 +898,10 @@ select {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.inline-flex {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.table {
|
||||
display: table;
|
||||
}
|
||||
@@ -918,6 +922,10 @@ select {
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
.h-4 {
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.h-5 {
|
||||
height: 1.25rem;
|
||||
}
|
||||
@@ -950,6 +958,10 @@ select {
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
.w-4 {
|
||||
width: 1rem;
|
||||
}
|
||||
|
||||
.w-5 {
|
||||
width: 1.25rem;
|
||||
}
|
||||
@@ -1048,6 +1060,10 @@ select {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.items-stretch {
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.justify-center {
|
||||
justify-content: center;
|
||||
}
|
||||
@@ -1118,10 +1134,6 @@ select {
|
||||
border-left-width: 2px;
|
||||
}
|
||||
|
||||
.border-l-4 {
|
||||
border-left-width: 4px;
|
||||
}
|
||||
|
||||
.border-r-2 {
|
||||
border-right-width: 2px;
|
||||
}
|
||||
@@ -1331,11 +1343,6 @@ select {
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
.text-3xl {
|
||||
font-size: 1.875rem;
|
||||
line-height: 2.25rem;
|
||||
}
|
||||
|
||||
.text-4xl {
|
||||
font-size: 2.25rem;
|
||||
line-height: 2.5rem;
|
||||
@@ -1369,6 +1376,10 @@ select {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.leading-4 {
|
||||
line-height: 1rem;
|
||||
}
|
||||
|
||||
.leading-normal {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user