serializers.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. from rest_framework import serializers
  2. from events.serializers import SentrySDKEventSerializer
  3. from glitchtip.serializers import FlexibleDateTimeField
  4. from .models import Span, TransactionEvent, TransactionGroup
  5. class TransactionGroupSerializer(serializers.ModelSerializer):
  6. avgDuration = serializers.DurationField(source="avg_duration", read_only=True)
  7. transactionCount = serializers.IntegerField(
  8. source="transaction_count", read_only=True
  9. )
  10. class Meta:
  11. model = TransactionGroup
  12. fields = [
  13. "id",
  14. "transaction",
  15. "project",
  16. "op",
  17. "method",
  18. "avgDuration",
  19. "transactionCount",
  20. ]
  21. class SpanSerializer(serializers.ModelSerializer):
  22. spanId = serializers.CharField(source="span_id", read_only=True)
  23. parentSpanId = serializers.CharField(source="parent_span_id", read_only=True)
  24. startTimestamp = serializers.DateTimeField(source="start_timestamp", read_only=True)
  25. start_timestamp = FlexibleDateTimeField(write_only=True)
  26. timestamp = FlexibleDateTimeField(write_only=True)
  27. class Meta:
  28. model = Span
  29. fields = [
  30. "spanId",
  31. "span_id",
  32. "parent_span_id",
  33. "parentSpanId",
  34. "op",
  35. "description",
  36. "startTimestamp",
  37. "start_timestamp",
  38. "timestamp",
  39. "tags",
  40. "data",
  41. ]
  42. extra_kwargs = {
  43. "start_timestamp": {"write_only": True},
  44. "span_id": {"write_only": True},
  45. "parent_span_id": {"write_only": True},
  46. }
  47. class TransactionEventSerializer(SentrySDKEventSerializer):
  48. type = serializers.CharField(required=False)
  49. contexts = serializers.JSONField()
  50. measurements = serializers.JSONField(required=False)
  51. spans = serializers.ListField(
  52. child=SpanSerializer(), required=False, allow_empty=True
  53. )
  54. start_timestamp = FlexibleDateTimeField()
  55. timestamp = FlexibleDateTimeField()
  56. transaction = serializers.CharField()
  57. def create(self, validated_data):
  58. data = validated_data
  59. contexts = data["contexts"]
  60. project = self.context.get("project")
  61. trace_id = contexts["trace"]["trace_id"]
  62. tags = []
  63. if environment := data.get("environment"):
  64. environment = self.get_environment(data["environment"], project)
  65. tags.append(("environment", environment.name))
  66. if release := data.get("release"):
  67. release = self.get_release(release, project)
  68. tags.append(("release", release.version))
  69. defaults = {}
  70. defaults["tags"] = {tag[0]: [tag[1]] for tag in tags}
  71. group, group_created = TransactionGroup.objects.get_or_create(
  72. project=self.context.get("project"),
  73. transaction=data["transaction"],
  74. op=contexts["trace"]["op"],
  75. method=data.get("request", {}).get("method"),
  76. defaults=defaults,
  77. )
  78. # Merge tags, only save if necessary
  79. update_group = False
  80. if not group_created:
  81. for tag in tags:
  82. if tag[0] not in group.tags:
  83. group.tags[tag[0]] = tag[1]
  84. update_group = True
  85. elif tag[1] not in group.tags[tag[0]]:
  86. group.tags[tag[0]].append(tag[1])
  87. update_group = True
  88. if update_group:
  89. group.save(update_fields=["tags"])
  90. transaction = TransactionEvent.objects.create(
  91. group=group,
  92. data={
  93. "request": data.get("request"),
  94. "sdk": data.get("sdk"),
  95. "platform": data.get("platform"),
  96. },
  97. trace_id=trace_id,
  98. event_id=data["event_id"],
  99. timestamp=data["timestamp"],
  100. start_timestamp=data["start_timestamp"],
  101. duration=data["timestamp"] - data["start_timestamp"],
  102. tags={tag[0]: tag[1] for tag in tags},
  103. )
  104. first_span = SpanSerializer(
  105. data=contexts["trace"]
  106. | {
  107. "start_timestamp": data["start_timestamp"],
  108. "timestamp": data["timestamp"],
  109. }
  110. )
  111. is_valid = first_span.is_valid()
  112. if is_valid:
  113. spans = data.get("spans", []) + [first_span.validated_data]
  114. else:
  115. spans = data.get("spans")
  116. if spans:
  117. Span.objects.bulk_create(
  118. [
  119. Span(
  120. transaction=transaction,
  121. **span,
  122. )
  123. for span in spans
  124. ]
  125. )
  126. return transaction
  127. class TransactionSerializer(serializers.ModelSerializer):
  128. eventId = serializers.UUIDField(source="pk")
  129. startTimestamp = serializers.DateTimeField(source="start_timestamp")
  130. transaction = serializers.SerializerMethodField()
  131. op = serializers.SerializerMethodField()
  132. method = serializers.SerializerMethodField()
  133. class Meta:
  134. model = TransactionEvent
  135. fields = (
  136. "eventId",
  137. "timestamp",
  138. "startTimestamp",
  139. "transaction",
  140. "op",
  141. "method",
  142. )
  143. def get_transaction(self, obj):
  144. return obj.group.transaction
  145. def get_op(self, obj):
  146. return obj.group.op
  147. def get_method(self, obj):
  148. return obj.group.transaction
  149. class TransactionDetailSerializer(TransactionSerializer):
  150. spans = SpanSerializer(source="span_set", many=True)
  151. class Meta(TransactionSerializer.Meta):
  152. fields = TransactionSerializer.Meta.fields + ("spans",)