Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce memory allocations during tag and metric serialization #294

Merged
merged 3 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 16 additions & 15 deletions lib/datadog/statsd/serialization/stat_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ def initialize(prefix, global_tags: [])
@tag_serializer = TagSerializer.new(global_tags)
end

def format(name, delta, type, tags: [], sample_rate: 1)
name = formated_name(name)
def format(metric_name, delta, type, tags: [], sample_rate: 1)
metric_name = formatted_metric_name(metric_name)

if sample_rate != 1
if tags_list = tag_serializer.format(tags)
"#{@prefix_str}#{name}:#{delta}|#{type}|@#{sample_rate}|##{tags_list}"
"#{@prefix_str}#{metric_name}:#{delta}|#{type}|@#{sample_rate}|##{tags_list}"
else
"#{@prefix_str}#{name}:#{delta}|#{type}|@#{sample_rate}"
"#{@prefix_str}#{metric_name}:#{delta}|#{type}|@#{sample_rate}"
end
else
if tags_list = tag_serializer.format(tags)
"#{@prefix_str}#{name}:#{delta}|#{type}|##{tags_list}"
"#{@prefix_str}#{metric_name}:#{delta}|#{type}|##{tags_list}"
else
"#{@prefix_str}#{name}:#{delta}|#{type}"
"#{@prefix_str}#{metric_name}:#{delta}|#{type}"
end
end
end
Expand All @@ -37,17 +37,18 @@ def global_tags
attr_reader :prefix
attr_reader :tag_serializer

def formated_name(name)
if name.is_a?(String)
# DEV: gsub is faster than dup.gsub!
formated = name.gsub('::', '.')
def formatted_metric_name(metric_name)
formatted = Symbol === metric_name ? metric_name.name : metric_name.to_s

if formatted.include?('::')
formatted = formatted.gsub('::', '.')
formatted.tr!(':|@', '_')
formatted
elsif formatted.include?(':') || formatted.include?('@') || formatted.include?('|')
formatted.tr(':|@', '_')
else
formated = name.to_s
formated.gsub!('::', '.')
formatted
end

formated.tr!(':|@', '_')
formated
end
end
end
Expand Down
4 changes: 3 additions & 1 deletion lib/datadog/statsd/serialization/tag_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ def to_tags_list(tags)
end

def escape_tag_content(tag)
tag.to_s.delete('|,')
tag = tag.to_s
return tag unless tag.include?('|')
tag.delete('|,')
end

def dd_tags(env = ENV)
Expand Down
16 changes: 16 additions & 0 deletions spec/statsd/serialization/stat_serializer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,22 @@
expect(subject.format('somecount', 42, 'c', tags: message_tags, sample_rate: 0.5)).to eq 'swag.somecount:42|c|@0.5|#globaltag1:value1,msgtag2:value2'
end
end

context "metric name contains unsupported characters" do
it 'does not alter the provided metric name when containing ::' do
input = 'somecount::test'
output = subject.format(input, 1, 'c')
expect(output).to eq 'somecount.test:1|c'
expect(input).to eq 'somecount::test'
end

it 'does not alter the provided metric name when containing :|@' do
input = 'somecount:|@test'
output = subject.format(input, 1, 'c')
expect(output).to eq 'somecount___test:1|c'
expect(input).to eq 'somecount:|@test'
end
end
end

context 'benchmark' do
Expand Down
7 changes: 7 additions & 0 deletions spec/statsd/serialization/tag_serializer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@
it 'formats frozen tags correctly' do
expect(subject.format(['name:foobarfoo'.freeze])).to eq 'name:foobarfoo'
end

it 'does not alter the provided tag value when containing unsupported characters' do
input = 'name|foobar'
output = subject.format([input])
expect(output).to eq 'namefoobar'
expect(input).to eq 'name|foobar'
end
end

context '[testing management of env vars]' do
Expand Down
Loading