33require "sentry/transport"
44require "sentry/log_event"
55require "sentry/log_event_buffer"
6+ require "sentry/metric_event"
7+ require "sentry/metric_event_buffer"
68require "sentry/utils/uuid"
79require "sentry/utils/encoding_helper"
810
@@ -21,6 +23,9 @@ class Client
2123 # @!visibility private
2224 attr_reader :log_event_buffer
2325
26+ # @!visibility private
27+ attr_reader :metric_event_buffer
28+
2429 # @!macro configuration
2530 attr_reader :configuration
2631
@@ -46,6 +51,10 @@ def initialize(configuration)
4651 if configuration . enable_logs
4752 @log_event_buffer = LogEventBuffer . new ( configuration , self ) . start
4853 end
54+
55+ if configuration . enable_metrics
56+ @metric_event_buffer = MetricEventBuffer . new ( configuration , self ) . start
57+ end
4958 end
5059
5160 # Applies the given scope's data to the event and sends it to Sentry.
@@ -102,6 +111,16 @@ def buffer_log_event(event, scope)
102111 event
103112 end
104113
114+ # Buffer a metric event to be sent later with other metrics in a single envelope
115+ # @param event [MetricEvent] the metric event to be buffered
116+ # @return [MetricEvent]
117+ def buffer_metric_event ( event , scope )
118+ return unless event . is_a? ( MetricEvent )
119+ event = scope . apply_to_telemetry ( event )
120+ @metric_event_buffer . add_metric ( event )
121+ event
122+ end
123+
105124 # Capture an envelope directly.
106125 # @param envelope [Envelope] the envelope to be captured.
107126 # @return [void]
@@ -115,6 +134,7 @@ def flush
115134 transport . flush if configuration . sending_to_dsn_allowed?
116135 spotlight_transport . flush if spotlight_transport
117136 @log_event_buffer &.flush
137+ @metric_event_buffer &.flush
118138 end
119139
120140 # Initializes an Event object with the given exception. Returns `nil` if the exception's class is excluded from reporting.
@@ -322,6 +342,55 @@ def send_logs(log_events)
322342 end
323343 end
324344
345+ # Send an envelope with batched metrics
346+ # @param metrics [Array<MetricEvent>] the metrics to send
347+ # @api private
348+ # @return [void]
349+ def send_metrics ( metrics )
350+ return if metrics . nil? || metrics . empty?
351+
352+ envelope = Envelope . new (
353+ event_id : Sentry ::Utils . uuid ,
354+ sent_at : Sentry . utc_now . iso8601 ,
355+ dsn : configuration . dsn ,
356+ sdk : Sentry . sdk_meta
357+ )
358+
359+ discarded_count = 0
360+ envelope_items = [ ]
361+
362+ if configuration . before_send_metric
363+ metrics . each do |metric |
364+ processed_metric = configuration . before_send_metric . call ( metric )
365+
366+ if processed_metric
367+ envelope_items << processed_metric . to_h
368+ else
369+ discarded_count += 1
370+ end
371+ end
372+
373+ envelope_items
374+ else
375+ envelope_items = metrics . map ( &:to_h )
376+ end
377+
378+ envelope . add_item (
379+ {
380+ type : "trace_metric" ,
381+ item_count : envelope_items . size ,
382+ content_type : "application/vnd.sentry.items.trace-metric+json"
383+ } ,
384+ { items : envelope_items }
385+ )
386+
387+ send_envelope ( envelope )
388+
389+ unless discarded_count . zero?
390+ transport . record_lost_event ( :before_send , "metric" , num : discarded_count )
391+ end
392+ end
393+
325394 # Send an envelope directly to Sentry.
326395 # @param envelope [Envelope] the envelope to be sent.
327396 # @return [void]
0 commit comments