ddtrace 0.47.0 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +4 -2
  3. data/.circleci/images/primary/Dockerfile-2.0.0 +11 -1
  4. data/.circleci/images/primary/Dockerfile-2.1.10 +11 -1
  5. data/.circleci/images/primary/Dockerfile-2.2.10 +11 -1
  6. data/.circleci/images/primary/Dockerfile-2.3.8 +10 -0
  7. data/.circleci/images/primary/Dockerfile-2.4.6 +10 -0
  8. data/.circleci/images/primary/Dockerfile-2.5.6 +10 -0
  9. data/.circleci/images/primary/Dockerfile-2.6.4 +10 -0
  10. data/.circleci/images/primary/Dockerfile-2.7.0 +10 -0
  11. data/.circleci/images/primary/Dockerfile-jruby-9.2-latest +10 -0
  12. data/.gitlab-ci.yml +18 -18
  13. data/.rubocop.yml +19 -0
  14. data/.rubocop_todo.yml +44 -3
  15. data/Appraisals +55 -1
  16. data/CHANGELOG.md +47 -1
  17. data/Gemfile +10 -0
  18. data/Rakefile +9 -0
  19. data/bin/ddtracerb +15 -0
  20. data/ddtrace.gemspec +4 -2
  21. data/docs/GettingStarted.md +36 -53
  22. data/docs/ProfilingDevelopment.md +88 -0
  23. data/integration/README.md +1 -2
  24. data/integration/apps/rack/Dockerfile +3 -0
  25. data/integration/apps/rack/script/build-images +1 -1
  26. data/integration/apps/rack/script/ci +1 -1
  27. data/integration/apps/rails-five/script/build-images +1 -1
  28. data/integration/apps/rails-five/script/ci +1 -1
  29. data/integration/apps/ruby/script/build-images +1 -1
  30. data/integration/apps/ruby/script/ci +1 -1
  31. data/integration/images/include/http-health-check +1 -1
  32. data/integration/images/wrk/scripts/entrypoint.sh +1 -1
  33. data/integration/script/build-images +1 -1
  34. data/lib/ddtrace.rb +1 -0
  35. data/lib/ddtrace/configuration.rb +39 -13
  36. data/lib/ddtrace/configuration/components.rb +85 -3
  37. data/lib/ddtrace/configuration/settings.rb +31 -0
  38. data/lib/ddtrace/contrib/active_record/configuration/makara_resolver.rb +30 -0
  39. data/lib/ddtrace/contrib/active_record/configuration/resolver.rb +9 -3
  40. data/lib/ddtrace/contrib/resque/configuration/settings.rb +17 -1
  41. data/lib/ddtrace/contrib/resque/patcher.rb +4 -4
  42. data/lib/ddtrace/contrib/resque/resque_job.rb +22 -1
  43. data/lib/ddtrace/contrib/shoryuken/configuration/settings.rb +1 -0
  44. data/lib/ddtrace/contrib/shoryuken/tracer.rb +7 -3
  45. data/lib/ddtrace/diagnostics/environment_logger.rb +1 -1
  46. data/lib/ddtrace/error.rb +2 -0
  47. data/lib/ddtrace/ext/profiling.rb +52 -0
  48. data/lib/ddtrace/ext/transport.rb +1 -0
  49. data/lib/ddtrace/metrics.rb +4 -0
  50. data/lib/ddtrace/profiling.rb +54 -0
  51. data/lib/ddtrace/profiling/backtrace_location.rb +32 -0
  52. data/lib/ddtrace/profiling/buffer.rb +41 -0
  53. data/lib/ddtrace/profiling/collectors/stack.rb +253 -0
  54. data/lib/ddtrace/profiling/encoding/profile.rb +31 -0
  55. data/lib/ddtrace/profiling/event.rb +13 -0
  56. data/lib/ddtrace/profiling/events/stack.rb +102 -0
  57. data/lib/ddtrace/profiling/exporter.rb +23 -0
  58. data/lib/ddtrace/profiling/ext/cpu.rb +54 -0
  59. data/lib/ddtrace/profiling/ext/cthread.rb +134 -0
  60. data/lib/ddtrace/profiling/ext/forking.rb +97 -0
  61. data/lib/ddtrace/profiling/flush.rb +41 -0
  62. data/lib/ddtrace/profiling/pprof/builder.rb +121 -0
  63. data/lib/ddtrace/profiling/pprof/converter.rb +85 -0
  64. data/lib/ddtrace/profiling/pprof/message_set.rb +12 -0
  65. data/lib/ddtrace/profiling/pprof/payload.rb +18 -0
  66. data/lib/ddtrace/profiling/pprof/pprof.proto +212 -0
  67. data/lib/ddtrace/profiling/pprof/pprof_pb.rb +81 -0
  68. data/lib/ddtrace/profiling/pprof/stack_sample.rb +90 -0
  69. data/lib/ddtrace/profiling/pprof/string_table.rb +10 -0
  70. data/lib/ddtrace/profiling/pprof/template.rb +114 -0
  71. data/lib/ddtrace/profiling/preload.rb +3 -0
  72. data/lib/ddtrace/profiling/profiler.rb +28 -0
  73. data/lib/ddtrace/profiling/recorder.rb +87 -0
  74. data/lib/ddtrace/profiling/scheduler.rb +84 -0
  75. data/lib/ddtrace/profiling/tasks/setup.rb +77 -0
  76. data/lib/ddtrace/profiling/transport/client.rb +12 -0
  77. data/lib/ddtrace/profiling/transport/http.rb +122 -0
  78. data/lib/ddtrace/profiling/transport/http/api.rb +43 -0
  79. data/lib/ddtrace/profiling/transport/http/api/endpoint.rb +90 -0
  80. data/lib/ddtrace/profiling/transport/http/api/instance.rb +36 -0
  81. data/lib/ddtrace/profiling/transport/http/api/spec.rb +40 -0
  82. data/lib/ddtrace/profiling/transport/http/builder.rb +28 -0
  83. data/lib/ddtrace/profiling/transport/http/client.rb +33 -0
  84. data/lib/ddtrace/profiling/transport/http/response.rb +21 -0
  85. data/lib/ddtrace/profiling/transport/io.rb +30 -0
  86. data/lib/ddtrace/profiling/transport/io/client.rb +27 -0
  87. data/lib/ddtrace/profiling/transport/io/response.rb +16 -0
  88. data/lib/ddtrace/profiling/transport/parcel.rb +17 -0
  89. data/lib/ddtrace/profiling/transport/request.rb +15 -0
  90. data/lib/ddtrace/profiling/transport/response.rb +8 -0
  91. data/lib/ddtrace/runtime/container.rb +11 -3
  92. data/lib/ddtrace/sampling/rule_sampler.rb +3 -9
  93. data/lib/ddtrace/tasks/exec.rb +48 -0
  94. data/lib/ddtrace/tasks/help.rb +14 -0
  95. data/lib/ddtrace/tracer.rb +21 -0
  96. data/lib/ddtrace/transport/io/client.rb +15 -8
  97. data/lib/ddtrace/transport/parcel.rb +4 -0
  98. data/lib/ddtrace/version.rb +3 -1
  99. data/lib/ddtrace/workers/runtime_metrics.rb +14 -1
  100. metadata +70 -9
@@ -0,0 +1,81 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: lib/ddtrace/profiling/pprof/pprof.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ Google::Protobuf::DescriptorPool.generated_pool.build do
7
+ add_message "perftools.profiles.Profile" do
8
+ repeated :sample_type, :message, 1, "perftools.profiles.ValueType"
9
+ repeated :sample, :message, 2, "perftools.profiles.Sample"
10
+ repeated :mapping, :message, 3, "perftools.profiles.Mapping"
11
+ repeated :location, :message, 4, "perftools.profiles.Location"
12
+ repeated :function, :message, 5, "perftools.profiles.Function"
13
+ repeated :string_table, :string, 6
14
+ optional :drop_frames, :int64, 7
15
+ optional :keep_frames, :int64, 8
16
+ optional :time_nanos, :int64, 9
17
+ optional :duration_nanos, :int64, 10
18
+ optional :period_type, :message, 11, "perftools.profiles.ValueType"
19
+ optional :period, :int64, 12
20
+ repeated :comment, :int64, 13
21
+ optional :default_sample_type, :int64, 14
22
+ end
23
+ add_message "perftools.profiles.ValueType" do
24
+ optional :type, :int64, 1
25
+ optional :unit, :int64, 2
26
+ end
27
+ add_message "perftools.profiles.Sample" do
28
+ repeated :location_id, :uint64, 1
29
+ repeated :value, :int64, 2
30
+ repeated :label, :message, 3, "perftools.profiles.Label"
31
+ end
32
+ add_message "perftools.profiles.Label" do
33
+ optional :key, :int64, 1
34
+ optional :str, :int64, 2
35
+ optional :num, :int64, 3
36
+ optional :num_unit, :int64, 4
37
+ end
38
+ add_message "perftools.profiles.Mapping" do
39
+ optional :id, :uint64, 1
40
+ optional :memory_start, :uint64, 2
41
+ optional :memory_limit, :uint64, 3
42
+ optional :file_offset, :uint64, 4
43
+ optional :filename, :int64, 5
44
+ optional :build_id, :int64, 6
45
+ optional :has_functions, :bool, 7
46
+ optional :has_filenames, :bool, 8
47
+ optional :has_line_numbers, :bool, 9
48
+ optional :has_inline_frames, :bool, 10
49
+ end
50
+ add_message "perftools.profiles.Location" do
51
+ optional :id, :uint64, 1
52
+ optional :mapping_id, :uint64, 2
53
+ optional :address, :uint64, 3
54
+ repeated :line, :message, 4, "perftools.profiles.Line"
55
+ optional :is_folded, :bool, 5
56
+ end
57
+ add_message "perftools.profiles.Line" do
58
+ optional :function_id, :uint64, 1
59
+ optional :line, :int64, 2
60
+ end
61
+ add_message "perftools.profiles.Function" do
62
+ optional :id, :uint64, 1
63
+ optional :name, :int64, 2
64
+ optional :system_name, :int64, 3
65
+ optional :filename, :int64, 4
66
+ optional :start_line, :int64, 5
67
+ end
68
+ end
69
+
70
+ module Perftools
71
+ module Profiles
72
+ Profile = Google::Protobuf::DescriptorPool.generated_pool.lookup("perftools.profiles.Profile").msgclass
73
+ ValueType = Google::Protobuf::DescriptorPool.generated_pool.lookup("perftools.profiles.ValueType").msgclass
74
+ Sample = Google::Protobuf::DescriptorPool.generated_pool.lookup("perftools.profiles.Sample").msgclass
75
+ Label = Google::Protobuf::DescriptorPool.generated_pool.lookup("perftools.profiles.Label").msgclass
76
+ Mapping = Google::Protobuf::DescriptorPool.generated_pool.lookup("perftools.profiles.Mapping").msgclass
77
+ Location = Google::Protobuf::DescriptorPool.generated_pool.lookup("perftools.profiles.Location").msgclass
78
+ Line = Google::Protobuf::DescriptorPool.generated_pool.lookup("perftools.profiles.Line").msgclass
79
+ Function = Google::Protobuf::DescriptorPool.generated_pool.lookup("perftools.profiles.Function").msgclass
80
+ end
81
+ end
@@ -0,0 +1,90 @@
1
+ require 'ddtrace/ext/profiling'
2
+ require 'ddtrace/profiling/events/stack'
3
+ require 'ddtrace/profiling/pprof/builder'
4
+ require 'ddtrace/profiling/pprof/converter'
5
+
6
+ module Datadog
7
+ module Profiling
8
+ module Pprof
9
+ # Builds a profile from a StackSample
10
+ class StackSample < Converter
11
+ SAMPLE_TYPES = {
12
+ cpu_time_ns: [
13
+ Datadog::Ext::Profiling::Pprof::VALUE_TYPE_CPU,
14
+ Datadog::Ext::Profiling::Pprof::VALUE_UNIT_NANOSECONDS
15
+ ],
16
+ wall_time_ns: [
17
+ Datadog::Ext::Profiling::Pprof::VALUE_TYPE_WALL,
18
+ Datadog::Ext::Profiling::Pprof::VALUE_UNIT_NANOSECONDS
19
+ ]
20
+ }.freeze
21
+
22
+ def self.sample_value_types
23
+ SAMPLE_TYPES
24
+ end
25
+
26
+ def add_events!(stack_samples)
27
+ new_samples = build_samples(stack_samples)
28
+ builder.samples.concat(new_samples)
29
+ end
30
+
31
+ def stack_sample_group_key(stack_sample)
32
+ stack_sample.hash
33
+ end
34
+
35
+ def build_samples(stack_samples)
36
+ groups = group_events(stack_samples, &method(:stack_sample_group_key))
37
+ groups.collect do |_group_key, group|
38
+ build_sample(group.sample, group.values)
39
+ end
40
+ end
41
+
42
+ def build_sample(stack_sample, values)
43
+ locations = builder.build_locations(
44
+ stack_sample.frames,
45
+ stack_sample.total_frame_count
46
+ )
47
+
48
+ Perftools::Profiles::Sample.new(
49
+ location_id: locations.collect(&:id),
50
+ value: values,
51
+ label: build_sample_labels(stack_sample)
52
+ )
53
+ end
54
+
55
+ def build_sample_values(stack_sample)
56
+ no_value = Datadog::Ext::Profiling::Pprof::SAMPLE_VALUE_NO_VALUE
57
+ values = super(stack_sample)
58
+ values[sample_value_index(:cpu_time_ns)] = stack_sample.cpu_time_interval_ns || no_value
59
+ values[sample_value_index(:wall_time_ns)] = stack_sample.wall_time_interval_ns || no_value
60
+ values
61
+ end
62
+
63
+ def build_sample_labels(stack_sample)
64
+ labels = [
65
+ Perftools::Profiles::Label.new(
66
+ key: builder.string_table.fetch(Datadog::Ext::Profiling::Pprof::LABEL_KEY_THREAD_ID),
67
+ str: builder.string_table.fetch(stack_sample.thread_id.to_s)
68
+ )
69
+ ]
70
+
71
+ unless stack_sample.trace_id.nil? || stack_sample.trace_id.zero?
72
+ labels << Perftools::Profiles::Label.new(
73
+ key: builder.string_table.fetch(Datadog::Ext::Profiling::Pprof::LABEL_KEY_TRACE_ID),
74
+ str: builder.string_table.fetch(stack_sample.trace_id.to_s)
75
+ )
76
+ end
77
+
78
+ unless stack_sample.span_id.nil? || stack_sample.span_id.zero?
79
+ labels << Perftools::Profiles::Label.new(
80
+ key: builder.string_table.fetch(Datadog::Ext::Profiling::Pprof::LABEL_KEY_SPAN_ID),
81
+ str: builder.string_table.fetch(stack_sample.span_id.to_s)
82
+ )
83
+ end
84
+
85
+ labels
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,10 @@
1
+ require 'ddtrace/utils/string_table'
2
+
3
+ module Datadog
4
+ module Profiling
5
+ module Pprof
6
+ # Tracks strings and returns IDs
7
+ class StringTable < Utils::StringTable; end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,114 @@
1
+ require 'ddtrace/profiling/pprof/payload'
2
+ require 'ddtrace/profiling/pprof/message_set'
3
+ require 'ddtrace/profiling/pprof/builder'
4
+
5
+ require 'ddtrace/profiling/events/stack'
6
+ require 'ddtrace/profiling/pprof/stack_sample'
7
+
8
+ module Datadog
9
+ module Profiling
10
+ module Pprof
11
+ # Converts a collection of profiling events into a Perftools::Profiles::Profile
12
+ class Template
13
+ DEFAULT_MAPPINGS = {
14
+ Events::StackSample => Pprof::StackSample
15
+ }.freeze
16
+
17
+ attr_reader \
18
+ :builder,
19
+ :converters,
20
+ :sample_type_mappings
21
+
22
+ def self.for_event_classes(event_classes)
23
+ # Build a map of event class --> converter class
24
+ mappings = event_classes.each_with_object({}) do |event_class, m|
25
+ converter_class = DEFAULT_MAPPINGS[event_class]
26
+ raise NoProfilingEventConversionError, event_class unless converter_class
27
+
28
+ m[event_class] = converter_class
29
+ end
30
+
31
+ new(mappings)
32
+ end
33
+
34
+ def initialize(mappings)
35
+ @builder = Builder.new
36
+ @converters = Hash.new { |_h, event_class| raise NoProfilingEventConversionError, event_class }
37
+ @sample_type_mappings = Hash.new { |_h, type| raise UnknownSampleTypeMappingError, type }
38
+
39
+ # Add default mapping
40
+ builder.mappings.fetch($PROGRAM_NAME, &builder.method(:build_mapping))
41
+
42
+ # Combine all sample types from each converter class
43
+ types = mappings.values.each_with_object({}) do |converter_class, t|
44
+ t.merge!(converter_class.sample_value_types)
45
+ end
46
+
47
+ # Build the sample types into sample type objects
48
+ types.each do |type_name, type_args|
49
+ index = nil
50
+
51
+ sample_type = builder.sample_types.fetch(*type_args) do |id, type, unit|
52
+ index = id
53
+ builder.build_value_type(type, unit)
54
+ end
55
+
56
+ # Create mapping between the type and index to which its assigned.
57
+ # Do this for faster lookup while building profile sample values.
58
+ sample_type_mappings[type_name] = index || builder.sample_types.messages.index(sample_type)
59
+ end
60
+
61
+ # Freeze them so they can't be modified.
62
+ # We don't want the number of sample types to vary between samples within the same profile.
63
+ builder.sample_types.freeze
64
+ sample_type_mappings.freeze
65
+
66
+ # Add converters
67
+ mappings.each do |event_class, converter_class|
68
+ converters[event_class] = converter_class.new(builder, sample_type_mappings)
69
+ end
70
+
71
+ converters.freeze
72
+ end
73
+
74
+ def add_events!(event_class, events)
75
+ converters[event_class].add_events!(events)
76
+ end
77
+
78
+ def to_pprof
79
+ profile = builder.build_profile
80
+ data = builder.encode_profile(profile)
81
+ types = sample_type_mappings.keys
82
+
83
+ Payload.new(data, types)
84
+ end
85
+
86
+ # Error when an unknown event type is given to be converted
87
+ class NoProfilingEventConversionError < ArgumentError
88
+ attr_reader :type
89
+
90
+ def initialize(type)
91
+ @type = type
92
+ end
93
+
94
+ def message
95
+ "Profiling event type '#{type}' cannot be converted to pprof."
96
+ end
97
+ end
98
+
99
+ # Error when the mapping of a sample type to value index is unknown
100
+ class UnknownSampleTypeMappingError < ArgumentError
101
+ attr_reader :type
102
+
103
+ def initialize(type)
104
+ @type = type
105
+ end
106
+
107
+ def message
108
+ "Mapping for sample value type '#{type}' is unknown."
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,3 @@
1
+ require 'ddtrace'
2
+
3
+ Datadog.profiler.start if Datadog.profiler
@@ -0,0 +1,28 @@
1
+ module Datadog
2
+ # Profiling entry point, which coordinates collectors and a scheduler
3
+ class Profiler
4
+ attr_reader \
5
+ :collectors,
6
+ :scheduler
7
+
8
+ def initialize(collectors, scheduler)
9
+ @collectors = collectors
10
+ @scheduler = scheduler
11
+ end
12
+
13
+ def start
14
+ collectors.each(&:start)
15
+ scheduler.start
16
+ end
17
+
18
+ def shutdown!
19
+ collectors.each do |collector|
20
+ collector.enabled = false
21
+ collector.stop(true)
22
+ end
23
+
24
+ scheduler.enabled = false
25
+ scheduler.stop(true)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,87 @@
1
+ require 'ddtrace/profiling/buffer'
2
+ require 'ddtrace/profiling/flush'
3
+
4
+ module Datadog
5
+ module Profiling
6
+ # Stores profiling events gathered by `Collector`s
7
+ class Recorder
8
+ attr_reader :max_size
9
+
10
+ def initialize(event_classes, max_size)
11
+ @buffers = {}
12
+ @last_flush_time = Time.now.utc
13
+ @max_size = max_size
14
+
15
+ # Add a buffer for each class
16
+ event_classes.each do |event_class|
17
+ @buffers[event_class] = Profiling::Buffer.new(max_size)
18
+ end
19
+ end
20
+
21
+ def [](event_class)
22
+ @buffers[event_class]
23
+ end
24
+
25
+ def push(events)
26
+ if events.is_a?(Array)
27
+ # Push multiple events
28
+ event_class = events.first.class
29
+ raise UnknownEventError, event_class unless @buffers.key?(event_class)
30
+
31
+ @buffers[event_class].concat(events)
32
+ else
33
+ # Push single event
34
+ event_class = events.class
35
+ raise UnknownEventError, event_class unless @buffers.key?(event_class)
36
+
37
+ @buffers[event_class].push(events)
38
+ end
39
+ end
40
+
41
+ def flush
42
+ event_count = 0
43
+
44
+ event_groups, start, finish = update_time do
45
+ @buffers.collect do |event_class, buffer|
46
+ events = buffer.pop
47
+ next if events.empty?
48
+
49
+ event_count += events.length
50
+ EventGroup.new(event_class, events)
51
+ end.compact
52
+ end
53
+
54
+ Flush.new(
55
+ start,
56
+ finish,
57
+ event_groups,
58
+ event_count
59
+ )
60
+ end
61
+
62
+ # Error when event of an unknown type is used with the Recorder
63
+ class UnknownEventError < StandardError
64
+ attr_reader :event_class
65
+
66
+ def initialize(event_class)
67
+ @event_class = event_class
68
+ end
69
+
70
+ def message
71
+ @message ||= "Unknown event class '#{event_class}' for profiling recorder."
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def update_time
78
+ start = @last_flush_time
79
+ result = yield
80
+ @last_flush_time = Time.now.utc
81
+
82
+ # Return event groups, start time, finish time
83
+ [result, start, @last_flush_time]
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,84 @@
1
+ require 'ddtrace/utils/time'
2
+
3
+ require 'ddtrace/worker'
4
+ require 'ddtrace/workers/polling'
5
+
6
+ module Datadog
7
+ module Profiling
8
+ # Periodically (every DEFAULT_INTERVAL seconds) takes data from the `Recorder` and pushes them to all configured
9
+ # `Exporter`s. Runs on its own background thread.
10
+ class Scheduler < Worker
11
+ include Workers::Polling
12
+
13
+ DEFAULT_INTERVAL = 60
14
+ MIN_INTERVAL = 0
15
+
16
+ attr_reader \
17
+ :exporters,
18
+ :recorder
19
+
20
+ def initialize(recorder, exporters, options = {})
21
+ @recorder = recorder
22
+ @exporters = [exporters].flatten
23
+
24
+ # Workers::Async::Thread settings
25
+ # Restart in forks by default
26
+ self.fork_policy = options[:fork_policy] || Workers::Async::Thread::FORK_POLICY_RESTART
27
+
28
+ # Workers::IntervalLoop settings
29
+ self.loop_base_interval = options[:interval] || DEFAULT_INTERVAL
30
+
31
+ # Workers::Polling settings
32
+ self.enabled = options.key?(:enabled) ? options[:enabled] == true : true
33
+ end
34
+
35
+ def start
36
+ perform
37
+ end
38
+
39
+ def perform
40
+ flush_and_wait
41
+ end
42
+
43
+ def loop_back_off?
44
+ false
45
+ end
46
+
47
+ def after_fork
48
+ # Clear recorder's buffers by flushing events.
49
+ # Objects from parent process will copy-on-write,
50
+ # and we don't want to send events for the wrong process.
51
+ recorder.flush
52
+ end
53
+
54
+ def flush_and_wait
55
+ run_time = Datadog::Utils::Time.measure do
56
+ flush_events
57
+ end
58
+
59
+ # Update wait time to try to wake consistently on time.
60
+ # Don't drop below the minimum interval.
61
+ self.loop_wait_time = [loop_base_interval - run_time, MIN_INTERVAL].max
62
+ end
63
+
64
+ def flush_events
65
+ # Get events from recorder
66
+ flush = recorder.flush
67
+
68
+ # Send events to each exporter
69
+ if flush.event_count > 0
70
+ exporters.each do |exporter|
71
+ begin
72
+ exporter.export(flush)
73
+ rescue StandardError => e
74
+ error_details = "Cause: #{e} Location: #{e.backtrace.first}"
75
+ Datadog.logger.error("Unable to export #{flush.event_count} profiling events. #{error_details}")
76
+ end
77
+ end
78
+ end
79
+
80
+ flush
81
+ end
82
+ end
83
+ end
84
+ end