Skip to content

Commit e126f72

Browse files
authored
Optimize LogEvent to reduce memory consumption (#2643)
* Simplify LogEvent * Optimize value_type * Optimize serialize * Optimize serialize_attributes * Stop creating intermediate iso timestamps * Fix double-timestamping * Move VALUE_TYPES up * Move TOKEN_REGEXP up * Remove unused DEFAULT_CONTEXT constant * Update CHANGELOG
1 parent 35c5214 commit e126f72

File tree

4 files changed

+56
-32
lines changed

4 files changed

+56
-32
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
- Support for `before_send_log` ([#2634](https://github.com/getsentry/sentry-ruby/pull/2634))
66

7+
### Bug Fixes
8+
9+
- Structured logging consumes way less memory now ([#2643](https://github.com/getsentry/sentry-ruby/pull/2643))
10+
711
## 5.24.0
812

913
### Features

sentry-ruby/lib/sentry/client.rb

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,12 +195,7 @@ def event_from_log(message, level:, **options)
195195

196196
attributes = options.reject { |k, _| k == :level || k == :severity }
197197

198-
LogEvent.new(
199-
level: level,
200-
body: message,
201-
timestamp: Time.now.to_f,
202-
attributes: attributes
203-
)
198+
LogEvent.new(level: level, body: message, attributes: attributes)
204199
end
205200

206201
# Initializes an Event object with the given Transaction object.

sentry-ruby/lib/sentry/log_event.rb

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,22 @@ module Sentry
44
# Event type that represents a log entry with its attributes
55
#
66
# @see https://develop.sentry.dev/sdk/telemetry/logs/#log-envelope-item-payload
7-
class LogEvent < Event
7+
class LogEvent
88
TYPE = "log"
99

1010
DEFAULT_PARAMETERS = [].freeze
1111
DEFAULT_ATTRIBUTES = {}.freeze
12-
DEFAULT_CONTEXT = {}.freeze
1312

1413
SERIALIZEABLE_ATTRIBUTES = %i[
1514
level
1615
body
1716
timestamp
17+
environment
18+
release
19+
server_name
1820
trace_id
1921
attributes
22+
contexts
2023
]
2124

2225
SENTRY_ATTRIBUTES = {
@@ -33,15 +36,40 @@ class LogEvent < Event
3336

3437
attr_accessor :level, :body, :template, :attributes
3538

36-
def initialize(configuration: Sentry.configuration, **options)
37-
super(configuration: configuration)
39+
attr_reader :configuration, *SERIALIZEABLE_ATTRIBUTES
40+
41+
SERIALIZERS = %i[
42+
attributes
43+
body
44+
level
45+
parent_span_id
46+
sdk_name
47+
sdk_version
48+
timestamp
49+
trace_id
50+
].map { |name| [name, :"serialize_#{name}"] }.to_h
51+
52+
VALUE_TYPES = Hash.new("string").merge!({
53+
TrueClass => "boolean",
54+
FalseClass => "boolean",
55+
Integer => "integer",
56+
Float => "double"
57+
}).freeze
3858

59+
TOKEN_REGEXP = /%\{(\w+)\}/
60+
61+
def initialize(configuration: Sentry.configuration, **options)
62+
@configuration = configuration
3963
@type = TYPE
64+
@server_name = configuration.server_name
65+
@environment = configuration.environment
66+
@release = configuration.release
67+
@timestamp = Sentry.utc_now
4068
@level = options.fetch(:level)
4169
@body = options[:body]
4270
@template = @body if is_template?
4371
@attributes = options[:attributes] || DEFAULT_ATTRIBUTES
44-
@contexts = DEFAULT_CONTEXT
72+
@contexts = {}
4573
end
4674

4775
def to_hash
@@ -53,9 +81,9 @@ def to_hash
5381
private
5482

5583
def serialize(name)
56-
serializer = :"serialize_#{name}"
84+
serializer = SERIALIZERS[name]
5785

58-
if respond_to?(serializer, true)
86+
if serializer
5987
__send__(serializer)
6088
else
6189
public_send(name)
@@ -75,7 +103,7 @@ def serialize_sdk_version
75103
end
76104

77105
def serialize_timestamp
78-
Time.parse(timestamp).to_f
106+
timestamp.to_f
79107
end
80108

81109
def serialize_trace_id
@@ -97,8 +125,10 @@ def serialize_body
97125
end
98126

99127
def serialize_attributes
100-
hash = attributes.each_with_object({}) do |(key, value), memo|
101-
memo[key] = attribute_hash(value)
128+
hash = {}
129+
130+
attributes.each do |key, value|
131+
hash[key] = attribute_hash(value)
102132
end
103133

104134
SENTRY_ATTRIBUTES.each do |key, name|
@@ -115,16 +145,7 @@ def attribute_hash(value)
115145
end
116146

117147
def value_type(value)
118-
case value
119-
when Integer
120-
"integer"
121-
when TrueClass, FalseClass
122-
"boolean"
123-
when Float
124-
"double"
125-
else
126-
"string"
127-
end
148+
VALUE_TYPES[value.class]
128149
end
129150

130151
def parameters
@@ -146,8 +167,6 @@ def parameters
146167
end
147168
end
148169

149-
TOKEN_REGEXP = /%\{(\w+)\}/
150-
151170
def template_tokens
152171
@template_tokens ||= body.scan(TOKEN_REGEXP).flatten.map(&:to_sym)
153172
end

sentry-ruby/lib/sentry/scope.rb

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,26 +46,32 @@ def clear
4646
# @param hint [Hash] the hint data that'll be passed to event processors.
4747
# @return [Event]
4848
def apply_to_event(event, hint = nil)
49-
unless event.is_a?(CheckInEvent)
49+
unless event.is_a?(CheckInEvent) || event.is_a?(LogEvent)
5050
event.tags = tags.merge(event.tags)
5151
event.user = user.merge(event.user)
5252
event.extra = extra.merge(event.extra)
5353
event.contexts = contexts.merge(event.contexts)
5454
event.transaction = transaction_name if transaction_name
5555
event.transaction_info = { source: transaction_source } if transaction_source
5656
event.fingerprint = fingerprint
57-
event.level = level unless event.is_a?(LogEvent)
57+
event.level = level
5858
event.breadcrumbs = breadcrumbs
5959
event.rack_env = rack_env if rack_env
6060
event.attachments = attachments
6161
end
6262

6363
if span
6464
event.contexts[:trace] ||= span.get_trace_context
65-
event.dynamic_sampling_context ||= span.get_dynamic_sampling_context
65+
66+
if event.respond_to?(:dynamic_sampling_context)
67+
event.dynamic_sampling_context ||= span.get_dynamic_sampling_context
68+
end
6669
else
6770
event.contexts[:trace] ||= propagation_context.get_trace_context
68-
event.dynamic_sampling_context ||= propagation_context.get_dynamic_sampling_context
71+
72+
if event.respond_to?(:dynamic_sampling_context)
73+
event.dynamic_sampling_context ||= propagation_context.get_dynamic_sampling_context
74+
end
6975
end
7076

7177
all_event_processors = self.class.global_event_processors + @event_processors

0 commit comments

Comments
 (0)