File: item.rb

package info (click to toggle)
ruby-sentry-ruby 5.28.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 672 kB
  • sloc: ruby: 6,118; makefile: 8; sh: 4
file content (88 lines) | stat: -rw-r--r-- 2,566 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# frozen_string_literal: true

module Sentry
  # @api private
  class Envelope::Item
    STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD = 500
    MAX_SERIALIZED_PAYLOAD_SIZE = 1024 * 1000

    SIZE_LIMITS = Hash.new(MAX_SERIALIZED_PAYLOAD_SIZE).update(
      "profile" => 1024 * 1000 * 50
    )

    attr_reader :size_limit, :headers, :payload, :type, :data_category

    # rate limits and client reports use the data_category rather than envelope item type
    def self.data_category(type)
      case type
      when "session", "attachment", "transaction", "profile", "span", "log" then type
      when "sessions" then "session"
      when "check_in" then "monitor"
      when "statsd", "metric_meta" then "metric_bucket"
      when "event" then "error"
      when "client_report" then "internal"
      else "default"
      end
    end

    def initialize(headers, payload)
      @headers = headers
      @payload = payload
      @type = headers[:type] || "event"
      @data_category = self.class.data_category(type)
      @size_limit = SIZE_LIMITS[type]
    end

    def to_s
      [JSON.generate(@headers), @payload.is_a?(String) ? @payload : JSON.generate(@payload)].join("\n")
    end

    def serialize
      result = to_s

      if result.bytesize > size_limit
        remove_breadcrumbs!
        result = to_s
      end

      if result.bytesize > size_limit
        reduce_stacktrace!
        result = to_s
      end

      [result, result.bytesize > size_limit]
    end

    def size_breakdown
      payload.map do |key, value|
        "#{key}: #{JSON.generate(value).bytesize}"
      end.join(", ")
    end

    private

    def remove_breadcrumbs!
      if payload.key?(:breadcrumbs)
        payload.delete(:breadcrumbs)
      elsif payload.key?("breadcrumbs")
        payload.delete("breadcrumbs")
      end
    end

    def reduce_stacktrace!
      if exceptions = payload.dig(:exception, :values) || payload.dig("exception", "values")
        exceptions.each do |exception|
          # in most cases there is only one exception (2 or 3 when have multiple causes), so we won't loop through this double condition much
          traces = exception.dig(:stacktrace, :frames) || exception.dig("stacktrace", "frames")

          if traces && traces.size > STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD
            size_on_both_ends = STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD / 2
            traces.replace(
              traces[0..(size_on_both_ends - 1)] + traces[-size_on_both_ends..-1],
            )
          end
        end
      end
    end
  end
end