Truncate input-data that exceeds max_length

Avoiding any (1406, "Data too long for column ...") on MySQL.

For the 'plainly provided' fields I followed the documented maximums which are
also our DB maximums. For calculated_* I harmonized with what Sentry &
GlitchTip both do (and which was already partially reflected in the code), i.e.
128 and 1024.
This commit is contained in:
Klaas van Schelven
2025-02-08 21:21:55 +01:00
parent 5e6413d793
commit a717dd7374
4 changed files with 58 additions and 12 deletions

View File

@@ -0,0 +1,20 @@
from django.db import migrations
from django.db.models import F
from django.db.models.functions import Substr, Length
def truncate_exception_type_128(apps, schema_editor):
Event = apps.get_model("events", "Event")
Event.objects.annotate(
l=Length('calculated_type')).filter(l__gte=128).update(calculated_type=Substr(F('calculated_type'), 1, 128))
class Migration(migrations.Migration):
dependencies = [
("events", "0004_b_squashed"),
]
operations = [
migrations.RunPython(truncate_exception_type_128),
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 4.2.19 on 2025-02-08 19:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("events", "0016_truncate_exception_type_128"),
]
operations = [
migrations.AlterField(
model_name="event",
name="calculated_type",
field=models.CharField(blank=True, default="", max_length=128),
),
migrations.AlterField(
model_name="event",
name="calculated_value",
field=models.TextField(blank=True, default="", max_length=1024),
),
]

View File

@@ -127,8 +127,8 @@ class Event(models.Model):
debug_info = models.CharField(max_length=255, blank=True, null=False, default="")
# denormalized/cached fields:
calculated_type = models.CharField(max_length=255, blank=True, null=False, default="")
calculated_value = models.CharField(max_length=255, blank=True, null=False, default="")
calculated_type = models.CharField(max_length=128, blank=True, null=False, default="")
calculated_value = models.TextField(max_length=1024, blank=True, null=False, default="")
# transaction = models.CharField(max_length=200, blank=True, null=False, default="") defined first-class above
last_frame_filename = models.CharField(max_length=255, blank=True, null=False, default="")
last_frame_module = models.CharField(max_length=255, blank=True, null=False, default="")
@@ -201,6 +201,9 @@ class Event(models.Model):
irrelevance_for_retention = get_random_irrelevance(stored_event_count)
# A note on truncation (max_length): the fields we truncate here are directly from the SDK, so they "should have
# been" truncated already. But we err on the side of caution: this is the kind of SDK error that we can, and
# just want to, paper over (it's not worth dropping the event for).
try:
event = cls.objects.create(
event_id=event_metadata["event_id"], # the metadata is the envelope's event_id, which takes precedence
@@ -212,25 +215,25 @@ class Event(models.Model):
data=json.dumps(parsed_data),
timestamp=parse_timestamp(parsed_data["timestamp"]),
platform=parsed_data["platform"],
platform=parsed_data["platform"][:64],
level=maybe_empty(parsed_data.get("level", "")),
logger=maybe_empty(parsed_data.get("logger", "")),
logger=maybe_empty(parsed_data.get("logger", ""))[:64],
# transaction=maybe_empty(parsed_data.get("transaction", "")), part of denormalized_fields
server_name=maybe_empty(parsed_data.get("server_name", "")),
release=maybe_empty(parsed_data.get("release", "")),
dist=maybe_empty(parsed_data.get("dist", "")),
server_name=maybe_empty(parsed_data.get("server_name", ""))[:255],
release=maybe_empty(parsed_data.get("release", ""))[:250],
dist=maybe_empty(parsed_data.get("dist", ""))[:64],
environment=maybe_empty(parsed_data.get("environment", "")),
environment=maybe_empty(parsed_data.get("environment", ""))[:64],
sdk_name=maybe_empty(parsed_data.get("", {}).get("name", "")),
sdk_version=maybe_empty(parsed_data.get("", {}).get("version", "")),
sdk_name=maybe_empty(parsed_data.get("", {}).get("name", ""))[:255],
sdk_version=maybe_empty(parsed_data.get("", {}).get("version", ""))[:255],
has_exception="exception" in parsed_data,
has_logentry="logentry" in parsed_data,
debug_info=event_metadata["debug_info"],
debug_info=event_metadata["debug_info"][:255],
digest_order=digest_order,
irrelevance_for_retention=irrelevance_for_retention,

View File

@@ -64,7 +64,7 @@ def get_exception_type_and_value_for_logmessage(data):
)
if message:
return "Log Message", message.splitlines()[0]
return "Log Message", message.splitlines()[0][:1024]
return "Log Message", "<no log message>"