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

Add metrics code locations #2263

Merged
merged 24 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
be9422d
metrics wip
sl0thentr0py Feb 16, 2024
ee59473
aggregator add impl
sl0thentr0py Feb 21, 2024
675292b
config and apis
sl0thentr0py Feb 21, 2024
73e5e04
encode statsd format and sanitization
sl0thentr0py Feb 22, 2024
9569bf9
capture envelope
sl0thentr0py Feb 22, 2024
8efde86
fix set
sl0thentr0py Feb 26, 2024
512408c
add transaction name to tags
sl0thentr0py Feb 26, 2024
bdac066
Specs
sl0thentr0py Feb 27, 2024
3f51c15
changelog
sl0thentr0py Feb 27, 2024
c1217cd
metric specs
sl0thentr0py Feb 27, 2024
8f9dabb
incr -> increment
sl0thentr0py Feb 29, 2024
ff3814f
Move config to separate metrics obj
sl0thentr0py Mar 5, 2024
f7163ef
Use scope name/source, not transaction
sl0thentr0py Mar 5, 2024
ff9792f
Remove is_json for envelope and use string check
sl0thentr0py Mar 11, 2024
9ba1a4e
trigger ci
sl0thentr0py Mar 11, 2024
478a78b
trigger ci
sl0thentr0py Mar 11, 2024
0e87bab
remove io-console pin
sl0thentr0py Mar 11, 2024
e6bbb90
Add Sentry::Metrics.timing API to measure blocks
sl0thentr0py Mar 4, 2024
7567daa
Merge remote-tracking branch 'origin/master' into neel/metrics/timing
sl0thentr0py Mar 12, 2024
116318b
Metric summaries on span
sl0thentr0py Mar 5, 2024
0df891d
Merge remote-tracking branch 'origin/master' into neel/metrics/span-a…
sl0thentr0py Mar 12, 2024
da14eaf
Add config.metrics.before_emit callback
sl0thentr0py Mar 8, 2024
088ccad
code locations
sl0thentr0py Mar 8, 2024
4107fd4
Merge remote-tracking branch 'origin/master' into neel/metrics/code-l…
sl0thentr0py Mar 12, 2024
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
Prev Previous commit
Next Next commit
add transaction name to tags
  • Loading branch information
sl0thentr0py committed Feb 26, 2024
commit 512408cde43b119cf082391767fb8ce39f76c96c
19 changes: 18 additions & 1 deletion sentry-ruby/lib/sentry/metrics/aggregator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@
}

def initialize(configuration, client)
@client = client
@logger = configuration.logger
@default_tags = { 'release' => configuration.release, 'environment' => configuration.environment }

Check warning on line 24 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L22-L24

Added lines #L22 - L24 were not covered by tests

@thread = nil
@exited = false
@mutex = Mutex.new

Check warning on line 28 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L26-L28

Added lines #L26 - L28 were not covered by tests

# buckets are a nested hash of timestamp -> bucket keys -> Metric instance
@buckets = {}

Check warning on line 31 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L31

Added line #L31 was not covered by tests

# the flush interval needs to be shifted once per startup to create jittering
@flush_shift = Random.rand * ROLLUP_IN_SECONDS

Check warning on line 34 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L34

Added line #L34 was not covered by tests
end

def add(type,
Expand All @@ -40,127 +40,144 @@
unit,
tags: {},
timestamp: nil)
return unless ensure_thread

Check warning on line 43 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L43

Added line #L43 was not covered by tests

timestamp = timestamp.to_i if timestamp.is_a?(Time)
timestamp ||= Sentry.utc_now.to_i

Check warning on line 46 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L45-L46

Added lines #L45 - L46 were not covered by tests

# this is integer division and thus takes the floor of the division
# and buckets into 10 second intervals
bucket_timestamp = (timestamp / ROLLUP_IN_SECONDS) * ROLLUP_IN_SECONDS

Check warning on line 50 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L50

Added line #L50 was not covered by tests

serialized_tags = serialize_tags(tags.merge(@default_tags))
serialized_tags = serialize_tags(get_updated_tags(tags))
bucket_key = [type, key, unit, serialized_tags]

Check warning on line 53 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L52-L53

Added lines #L52 - L53 were not covered by tests

@mutex.synchronize do
@buckets[bucket_timestamp] ||= {}

Check warning on line 56 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L55-L56

Added lines #L55 - L56 were not covered by tests

if @buckets[bucket_timestamp][bucket_key]
@buckets[bucket_timestamp][bucket_key].add(value)

Check warning on line 59 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L58-L59

Added lines #L58 - L59 were not covered by tests
else
@buckets[bucket_timestamp][bucket_key] = METRIC_TYPES[type].new(value)

Check warning on line 61 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L61

Added line #L61 was not covered by tests
end
end
end

def flush(force: false)
log_debug("[Metrics::Aggregator] current bucket state: #{@buckets}")

Check warning on line 67 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L67

Added line #L67 was not covered by tests

flushable_buckets = get_flushable_buckets!(force)
return if flushable_buckets.empty?

Check warning on line 70 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L69-L70

Added lines #L69 - L70 were not covered by tests

payload = serialize_buckets(flushable_buckets)
envelope = Envelope.new
envelope.add_item(

Check warning on line 74 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L72-L74

Added lines #L72 - L74 were not covered by tests
{ type: 'statsd', length: payload.bytesize },
payload,
is_json: false
)

log_debug("[Metrics::Aggregator] flushing buckets: #{flushable_buckets}")
log_debug("[Metrics::Aggregator] payload: #{payload}")

Check warning on line 81 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L80-L81

Added lines #L80 - L81 were not covered by tests

Sentry.background_worker.perform do
@client.transport.send_envelope(envelope)

Check warning on line 84 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L83-L84

Added lines #L83 - L84 were not covered by tests
end
end

def kill
log_debug('[Metrics::Aggregator] killing thread')

Check warning on line 89 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L89

Added line #L89 was not covered by tests

@exited = true
@thread&.kill

Check warning on line 92 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L91-L92

Added lines #L91 - L92 were not covered by tests
end

private

def ensure_thread
return false if @exited
return true if @thread&.alive?

Check warning on line 99 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L98-L99

Added lines #L98 - L99 were not covered by tests

@thread = Thread.new do
loop do

Check warning on line 102 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L101-L102

Added lines #L101 - L102 were not covered by tests
# TODO use event for force flush later
sleep(FLUSH_INTERVAL)
flush

Check warning on line 105 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L104-L105

Added lines #L104 - L105 were not covered by tests
end
end

true

Check warning on line 109 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L109

Added line #L109 was not covered by tests
rescue ThreadError
log_debug('[Metrics::Aggregator] thread creation failed')
@exited = true
false

Check warning on line 113 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L111-L113

Added lines #L111 - L113 were not covered by tests
end

# important to sort for key consistency
def serialize_tags(tags)
tags.flat_map do |k, v|
if v.is_a?(Array)
v.map { |x| [k.to_s, x.to_s] }

Check warning on line 120 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L118-L120

Added lines #L118 - L120 were not covered by tests
else
[[k.to_s, v.to_s]]

Check warning on line 122 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L122

Added line #L122 was not covered by tests
end
end.sort
end

def get_flushable_buckets!(force)
@mutex.synchronize do
flushable_buckets = {}

Check warning on line 129 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L128-L129

Added lines #L128 - L129 were not covered by tests

if force
flushable_buckets = @buckets
@buckets = {}

Check warning on line 133 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L131-L133

Added lines #L131 - L133 were not covered by tests
else
cutoff = Sentry.utc_now.to_i - ROLLUP_IN_SECONDS - @flush_shift
flushable_buckets = @buckets.select { |k, _| k <= cutoff }
@buckets.reject! { |k, _| k <= cutoff }

Check warning on line 137 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L135-L137

Added lines #L135 - L137 were not covered by tests
end

flushable_buckets

Check warning on line 140 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L140

Added line #L140 was not covered by tests
end
end

# serialize buckets to statsd format
def serialize_buckets(buckets)
buckets.map do |timestamp, timestamp_buckets|
timestamp_buckets.map do |metric_key, metric|
type, key, unit, tags = metric_key
values = metric.serialize.join(':')
sanitized_tags = tags.map { |k, v| "#{sanitize_key(k)}:#{sanitize_value(v)}" }.join(',')

Check warning on line 150 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L146-L150

Added lines #L146 - L150 were not covered by tests

"#{sanitize_key(key)}@#{unit}:#{values}|#{type}|\##{sanitized_tags}|T#{timestamp}"

Check warning on line 152 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L152

Added line #L152 was not covered by tests
end
end.flatten.join("\n")
end

def sanitize_key(key)
key.gsub(KEY_SANITIZATION_REGEX, '_')

Check warning on line 158 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L158

Added line #L158 was not covered by tests
end

def sanitize_value(value)
value.gsub(VALUE_SANITIZATION_REGEX, '')

Check warning on line 162 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L162

Added line #L162 was not covered by tests
end

def get_transaction_name
transaction = Sentry.get_current_scope&.get_transaction
return nil unless transaction
return nil if transaction.source_low_quality?

Check warning on line 168 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L166-L168

Added lines #L166 - L168 were not covered by tests

transaction.name

Check warning on line 170 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L170

Added line #L170 was not covered by tests
end

def get_updated_tags(tags)
updated_tags = @default_tags.merge(tags)

Check warning on line 174 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L174

Added line #L174 was not covered by tests

transaction_name = get_transaction_name
updated_tags['transaction'] = transaction_name if transaction_name

Check warning on line 177 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L176-L177

Added lines #L176 - L177 were not covered by tests

updated_tags

Check warning on line 179 in sentry-ruby/lib/sentry/metrics/aggregator.rb

View check run for this annotation

Codecov / codecov/patch

sentry-ruby/lib/sentry/metrics/aggregator.rb#L179

Added line #L179 was not covered by tests
end
end
end
end
10 changes: 5 additions & 5 deletions sentry-ruby/lib/sentry/transaction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,11 @@ def start_profiler!
profiler.start
end

# These are high cardinality and thus bad
def source_low_quality?
source == :url
end

protected

def init_span_recorder(limit = 1000)
Expand Down Expand Up @@ -337,11 +342,6 @@ def populate_head_baggage
@baggage = Baggage.new(items, mutable: false)
end

# These are high cardinality and thus bad
def source_low_quality?
source == :url
end

class SpanRecorder
attr_reader :max_length, :spans

Expand Down
Loading