trace_viz 0.0.1 → 0.0.2

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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +34 -0
  3. data/README.md +130 -38
  4. data/examples/example.cast +285 -0
  5. data/examples/example.rb +94 -23
  6. data/lib/trace_viz/adapters/base_adapter.rb +0 -2
  7. data/lib/trace_viz/adapters/trace_point_adapter.rb +17 -11
  8. data/lib/trace_viz/collectors/base_collector.rb +83 -0
  9. data/lib/trace_viz/collectors/depth_manager.rb +37 -0
  10. data/lib/trace_viz/collectors/evaluators/base_evaluator.rb +23 -0
  11. data/lib/trace_viz/collectors/evaluators/filter_evaluator.rb +30 -0
  12. data/lib/trace_viz/collectors/evaluators/hidden_evaluator.rb +21 -0
  13. data/lib/trace_viz/collectors/filters/base_filter.rb +23 -0
  14. data/lib/trace_viz/collectors/filters/exclude_classes_filter.rb +28 -0
  15. data/lib/trace_viz/collectors/filters/exclude_default_classes_filter.rb +38 -0
  16. data/lib/trace_viz/collectors/filters/exclude_gems_filter.rb +30 -0
  17. data/lib/trace_viz/collectors/filters/exclude_internal_call_filter.rb +31 -0
  18. data/lib/trace_viz/collectors/filters/exclude_rails_framework_filter.rb +38 -0
  19. data/lib/trace_viz/collectors/filters/include_classes_filter.rb +28 -0
  20. data/lib/trace_viz/collectors/filters/include_gems_filter.rb +54 -0
  21. data/lib/trace_viz/collectors/filters/registry.rb +59 -0
  22. data/lib/trace_viz/collectors/matchers/trace_point_action_matcher.rb +36 -0
  23. data/lib/trace_viz/collectors/matchers/within_depth_matcher.rb +25 -0
  24. data/lib/trace_viz/collectors/trace_point_collector.rb +51 -0
  25. data/lib/trace_viz/collectors/trace_stats.rb +21 -0
  26. data/lib/trace_viz/config/copier.rb +38 -0
  27. data/lib/trace_viz/config/validator.rb +74 -0
  28. data/lib/trace_viz/configuration.rb +36 -30
  29. data/lib/trace_viz/context/config_context.rb +1 -1
  30. data/lib/trace_viz/context/manager.rb +17 -21
  31. data/lib/trace_viz/context/map.rb +29 -0
  32. data/lib/trace_viz/context/registry.rb +37 -0
  33. data/lib/trace_viz/context/tracking/active_calls.rb +37 -0
  34. data/lib/trace_viz/context/tracking_context.rb +7 -2
  35. data/lib/trace_viz/context.rb +2 -2
  36. data/lib/trace_viz/core/tracer.rb +1 -0
  37. data/lib/trace_viz/defaults.rb +139 -0
  38. data/lib/trace_viz/exporters/base_exporter.rb +84 -0
  39. data/lib/trace_viz/exporters/formatters/base_formatter.rb +12 -0
  40. data/lib/trace_viz/exporters/formatters/method_call_formatter.rb +21 -0
  41. data/lib/trace_viz/exporters/formatters/method_return_formatter.rb +22 -0
  42. data/lib/trace_viz/exporters/text_exporter.rb +15 -0
  43. data/lib/trace_viz/exporters/transformers/base_transformer.rb +25 -0
  44. data/lib/trace_viz/exporters/transformers/text_transformer.rb +28 -0
  45. data/lib/trace_viz/formatters/base_formatter.rb +42 -0
  46. data/lib/trace_viz/formatters/helpers/depth_helper.rb +21 -0
  47. data/lib/trace_viz/formatters/helpers/indent_helper.rb +15 -0
  48. data/lib/trace_viz/formatters/helpers/method_details_helper.rb +15 -0
  49. data/lib/trace_viz/formatters/helpers/params_helper.rb +26 -0
  50. data/lib/trace_viz/formatters/helpers/result_helper.rb +21 -0
  51. data/lib/trace_viz/formatters/helpers/source_helper.rb +21 -0
  52. data/lib/trace_viz/formatters/helpers/time_helper.rb +15 -0
  53. data/lib/trace_viz/logger.rb +37 -47
  54. data/lib/trace_viz/loggers/trace_builder.rb +30 -0
  55. data/lib/trace_viz/loggers/trace_formatters/base_formatter.rb +32 -0
  56. data/lib/trace_viz/loggers/trace_formatters/method_call_formatter.rb +21 -0
  57. data/lib/trace_viz/loggers/trace_formatters/method_return_formatter.rb +22 -0
  58. data/lib/trace_viz/loggers/trace_logger.rb +38 -0
  59. data/lib/trace_viz/loggers/trace_stats_logger.rb +33 -0
  60. data/lib/trace_viz/trace_data/base.rb +56 -0
  61. data/lib/trace_viz/trace_data/trace_point/base.rb +68 -0
  62. data/lib/trace_viz/trace_data/trace_point/method_call.rb +42 -0
  63. data/lib/trace_viz/trace_data/trace_point/method_return.rb +25 -0
  64. data/lib/trace_viz/trace_data/trace_point_builder.rb +23 -0
  65. data/lib/trace_viz/utils/colorize.rb +12 -23
  66. data/lib/trace_viz/utils/format_utils.rb +67 -0
  67. data/lib/trace_viz/version.rb +1 -1
  68. metadata +58 -13
  69. data/lib/trace_viz/adapters/trace_point/depth_manager.rb +0 -34
  70. data/lib/trace_viz/adapters/trace_point/event_handler.rb +0 -36
  71. data/lib/trace_viz/adapters/trace_point/trace_data.rb +0 -89
  72. data/lib/trace_viz/adapters/trace_point/trace_formatter.rb +0 -95
  73. data/lib/trace_viz/adapters/trace_point/trace_logger.rb +0 -44
  74. data/lib/trace_viz/context/manager/context_map.rb +0 -31
  75. data/lib/trace_viz/context/manager/context_operations.rb +0 -60
  76. data/lib/trace_viz/context/manager/context_registry.rb +0 -20
  77. data/lib/trace_viz/context/manager/context_validation.rb +0 -34
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "trace_viz/context"
4
+ require "trace_viz/loggers/trace_logger"
5
+ require_relative "evaluators/filter_evaluator"
6
+ require_relative "evaluators/hidden_evaluator"
7
+
8
+ module TraceViz
9
+ module Collectors
10
+ class BaseCollector
11
+ attr_reader :collection, :stats
12
+
13
+ # To implement collect trace data from the given event,
14
+ # you need to enter the `config` context to perform the evaluation.
15
+ def initialize
16
+ @tracker = Context.for(:tracking)
17
+ @stats = TraceStats.new
18
+
19
+ @collection = []
20
+
21
+ @filter_evaluator = Evaluators::FilterEvaluator.new
22
+ @hidden_evaluator = Evaluators::HiddenEvaluator.new
23
+ end
24
+
25
+ def collect(event)
26
+ return unless collectible?(event)
27
+
28
+ trace_data = build_trace(event)
29
+ return unless valid?(trace_data)
30
+
31
+ trace_data = update_trace_depth(trace_data)
32
+ return if hidden?(trace_data)
33
+
34
+ log_trace(trace_data)
35
+ store_trace(trace_data)
36
+ end
37
+
38
+ def clear
39
+ @collection = []
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :tracker,
45
+ :filter_evaluator,
46
+ :hidden_evaluator
47
+
48
+ # Checks if trace data is collectible.
49
+ def collectible?(event)
50
+ raise NotImplementedError
51
+ end
52
+
53
+ # Validates trace data against filters.
54
+ def valid?(trace_data)
55
+ filter_evaluator.pass?(trace_data)
56
+ end
57
+
58
+ # Checks if trace data should be hidden.
59
+ def hidden?(trace_data)
60
+ hidden_evaluator.pass?(trace_data)
61
+ end
62
+
63
+ # Builds trace data from the given data.
64
+ def build_trace(event)
65
+ raise NotImplementedError
66
+ end
67
+
68
+ def update_trace_depth(trace_data)
69
+ raise NotImplementedError
70
+ end
71
+
72
+ def log_trace(trace_data)
73
+ Loggers::TraceLogger.log(trace_data)
74
+ end
75
+
76
+ def store_trace(trace_data)
77
+ stats.update(trace_data)
78
+
79
+ @collection << trace_data
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TraceViz
4
+ module Collectors
5
+ class DepthManager
6
+ def initialize
7
+ @tracker = Context.for(:tracking)
8
+ end
9
+
10
+ def align(trace_data)
11
+ case trace_data.event
12
+ when :call
13
+ push_to_call_stack(trace_data)
14
+ when :return
15
+ pop_from_call_stack(trace_data)
16
+ end
17
+ trace_data
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :tracker
23
+
24
+ # Increment the depth
25
+ def push_to_call_stack(trace_data)
26
+ trace_data.depth = tracker.current_depth
27
+ tracker.active_calls.push(trace_data)
28
+ end
29
+
30
+ # Decrement the depth
31
+ def pop_from_call_stack(trace_data)
32
+ tracker.active_calls.pop
33
+ trace_data.depth = tracker.current_depth
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "trace_viz/context"
4
+
5
+ module TraceViz
6
+ module Collectors
7
+ module Evaluators
8
+ class BaseEvaluator
9
+ def initialize
10
+ @config = Context.for(:config).configuration
11
+ end
12
+
13
+ def pass?(trace_data)
14
+ raise NotImplementedError
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :config
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "trace_viz/collectors/filters/registry"
4
+ require_relative "base_evaluator"
5
+
6
+ module TraceViz
7
+ module Collectors
8
+ module Evaluators
9
+ class FilterEvaluator < BaseEvaluator
10
+ def initialize
11
+ super()
12
+
13
+ @filters = build_filters.freeze
14
+ end
15
+
16
+ def pass?(trace_data)
17
+ filters.all? { |filter| filter.apply?(trace_data) }
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :filters
23
+
24
+ def build_filters
25
+ Collectors::Filters::Registry.build(config.filters)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_evaluator"
4
+
5
+ module TraceViz
6
+ module Collectors
7
+ module Evaluators
8
+ class HiddenEvaluator < BaseEvaluator
9
+ def pass?(trace_data)
10
+ !allowed_events.include?(trace_data.event)
11
+ end
12
+
13
+ private
14
+
15
+ def allowed_events
16
+ config.execution[:show_trace_events]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "trace_viz/context"
4
+
5
+ module TraceViz
6
+ module Collectors
7
+ module Filters
8
+ class BaseFilter
9
+ def initialize
10
+ @config = Context.for(:config).configuration
11
+ end
12
+
13
+ def apply?(trace_data)
14
+ raise NotImplementedError
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :config
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_filter"
4
+
5
+ module TraceViz
6
+ module Collectors
7
+ module Filters
8
+ class ExcludeClassesFilter < BaseFilter
9
+ def initialize(**options)
10
+ super()
11
+ @excluded_classes = options[:classes].map(&:to_s).freeze
12
+ end
13
+
14
+ def apply?(trace_data)
15
+ !exclude_class?(trace_data.klass)
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :excluded_classes
21
+
22
+ def exclude_class?(klass)
23
+ excluded_classes.include?(klass.to_s)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+ require_relative "base_filter"
5
+
6
+ module TraceViz
7
+ module Collectors
8
+ module Filters
9
+ class ExcludeDefaultClassesFilter < BaseFilter
10
+ RUBY_CORE_CLASSES = Set.new([
11
+ Object,
12
+ String,
13
+ Array,
14
+ Hash,
15
+ Numeric,
16
+ Integer,
17
+ Float,
18
+ Symbol,
19
+ Kernel,
20
+ Module,
21
+ Class,
22
+ Range,
23
+ Regexp,
24
+ ].map(&:to_s).freeze)
25
+
26
+ def apply?(trace_data)
27
+ !excluded_class?(trace_data.klass)
28
+ end
29
+
30
+ private
31
+
32
+ def excluded_class?(klass)
33
+ RUBY_CORE_CLASSES.include?(klass.to_s)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_filter"
4
+
5
+ module TraceViz
6
+ module Collectors
7
+ module Filters
8
+ class ExcludeGemsFilter < BaseFilter
9
+ def initialize(**options)
10
+ super()
11
+ @excluded_gems = options[:gems].map do |gem_name|
12
+ ::Gem.loaded_specs[gem_name]&.full_gem_path
13
+ end.compact.freeze
14
+ end
15
+
16
+ def apply?(trace_data)
17
+ !excluded_gem?(trace_data.path)
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :excluded_gems
23
+
24
+ def excluded_gem?(path)
25
+ excluded_gems.any? { |gem_path| path.start_with?(gem_path) }
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_filter"
4
+
5
+ module TraceViz
6
+ module Collectors
7
+ module Filters
8
+ class ExcludeInternalCallFilter < BaseFilter
9
+ INTERNAL_PATH_IDENTIFIER = "<internal:"
10
+ INTERNAL_CLASS_PREFIX = "TracePoint"
11
+
12
+ def apply?(trace_data)
13
+ [
14
+ internal_path?(trace_data.path),
15
+ internal_class?(trace_data.klass),
16
+ ].none?
17
+ end
18
+
19
+ private
20
+
21
+ def internal_path?(path)
22
+ path.include?(INTERNAL_PATH_IDENTIFIER)
23
+ end
24
+
25
+ def internal_class?(klass)
26
+ klass.to_s.start_with?(INTERNAL_CLASS_PREFIX)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_filter"
4
+
5
+ module TraceViz
6
+ module Collectors
7
+ module Filters
8
+ class ExcludeRailsFrameworkFilter < BaseFilter
9
+ RAILS_MODULES = [
10
+ "ActiveSupport",
11
+ "ActiveModel",
12
+ "ActiveRecord",
13
+ "ActionPack",
14
+ "ActionController",
15
+ "ActionView",
16
+ "ActionMailer",
17
+ "ActiveJob",
18
+ "ActionCable",
19
+ "ActionDispatch",
20
+ "ActiveStorage",
21
+ "ActionMailbox",
22
+ "ActionText",
23
+ "Rails",
24
+ ].freeze
25
+
26
+ def apply?(trace_data)
27
+ !rails_related?(trace_data.klass)
28
+ end
29
+
30
+ private
31
+
32
+ def rails_related?(klass)
33
+ RAILS_MODULES.any? { |mod| klass.to_s.start_with?(mod) }
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_filter"
4
+
5
+ module TraceViz
6
+ module Collectors
7
+ module Filters
8
+ class IncludeClassesFilter < BaseFilter
9
+ def initialize(**options)
10
+ super()
11
+ @allowed_classes = options[:classes].map(&:to_s).freeze
12
+ end
13
+
14
+ def apply?(trace_data)
15
+ include_class?(trace_data.klass)
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :allowed_classes
21
+
22
+ def include_class?(klass)
23
+ allowed_classes.include?(klass.to_s)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_filter"
4
+
5
+ module TraceViz
6
+ module Collectors
7
+ module Filters
8
+ class IncludeGemsFilter < BaseFilter
9
+ DEFAULT_OPTIONS = {
10
+ app_running: true,
11
+ gems: [],
12
+ }.freeze
13
+
14
+ def initialize(**options)
15
+ super()
16
+ @include_app = options.fetch(:app_running, DEFAULT_OPTIONS[:app_running])
17
+ @app_path = options[:app_path] || detect_app_path
18
+ @app_path.freeze
19
+ @included_gems = options.fetch(:gems, DEFAULT_OPTIONS[:gems]).map do |gem_name|
20
+ ::Gem.loaded_specs[gem_name]&.full_gem_path
21
+ end.compact.freeze
22
+ end
23
+
24
+ def apply?(trace_data)
25
+ app_path_included?(trace_data.path) || included_gem?(trace_data.path)
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :include_app, :app_path, :included_gems
31
+
32
+ def included_gem?(path)
33
+ included_gems.any? { |gem_path| path.start_with?(gem_path) }
34
+ end
35
+
36
+ def app_path_included?(path)
37
+ include_app && path.start_with?(app_path)
38
+ end
39
+
40
+ def detect_app_path
41
+ if defined?(Bundler)
42
+ Bundler.root.to_s
43
+ else
44
+ # Use the directory of the currently running script
45
+ File.expand_path("..", $PROGRAM_NAME)
46
+ end
47
+ rescue StandardError
48
+ # Fallback to current working directory
49
+ Dir.pwd
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "include_classes_filter"
4
+ require_relative "include_gems_filter"
5
+ require_relative "exclude_internal_call_filter"
6
+ require_relative "exclude_gems_filter"
7
+ require_relative "exclude_rails_framework_filter"
8
+ require_relative "exclude_default_classes_filter"
9
+ require_relative "exclude_classes_filter"
10
+
11
+ module TraceViz
12
+ module Collectors
13
+ module Filters
14
+ class Registry
15
+ FILTERS = {
16
+ include_classes: IncludeClassesFilter,
17
+ include_gems: IncludeGemsFilter,
18
+ exclude_internal_call: ExcludeInternalCallFilter,
19
+ exclude_gems: ExcludeGemsFilter,
20
+ exclude_rails_framework: ExcludeRailsFrameworkFilter,
21
+ exclude_default_classes: ExcludeDefaultClassesFilter,
22
+ exclude_classes: ExcludeClassesFilter,
23
+ }.freeze
24
+
25
+ class << self
26
+ def build(filters)
27
+ filters.each_with_object([]) do |filter, result|
28
+ case filter
29
+ when Symbol
30
+ # Handle simple filters
31
+ # (e.g., :depth, :exclude_internal_call)
32
+ klass = fetch_filter_class(filter)
33
+ result << klass.new
34
+ when Hash
35
+ # Handle complex filters with options
36
+ # (e.g., { include_classes: { classes: [Example] } })
37
+ filter.each do |filter_key, options|
38
+ klass = fetch_filter_class(filter_key)
39
+ result << klass.new(**options)
40
+ end
41
+ else
42
+ raise ArgumentError, "Invalid filter format: #{filter.inspect}"
43
+ end
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def fetch_filter_class(filter_key)
50
+ FILTERS.fetch(filter_key) do
51
+ available_keys = FILTERS.keys.join(", ")
52
+ raise ArgumentError, "Unknown filter: #{filter_key}. Available filters are: #{available_keys}"
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TraceViz
4
+ module Collectors
5
+ module Matchers
6
+ class TracePointActionMatcher
7
+ def initialize
8
+ @tracker = Context.for(:tracking)
9
+ end
10
+
11
+ def matches?(trace_point)
12
+ current_action_id == build_action_id(trace_point)
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :tracker
18
+
19
+ def current_action
20
+ tracker.active_calls.current
21
+ end
22
+
23
+ def current_action_id
24
+ current_action&.action_id
25
+ end
26
+
27
+ def build_action_id(trace_point)
28
+ [
29
+ trace_point.self.object_id,
30
+ trace_point.callee_id,
31
+ ].join("_")
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TraceViz
4
+ module Collectors
5
+ module Matchers
6
+ class WithinDepthMatcher
7
+ def initialize
8
+ @config = Context.for(:config).configuration
9
+ end
10
+
11
+ def matches?(depth)
12
+ depth <= max_depth
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :config
18
+
19
+ def max_depth
20
+ config.general[:max_display_depth]
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "trace_viz/trace_data/trace_point_builder"
4
+ require_relative "base_collector"
5
+ require_relative "matchers/trace_point_action_matcher"
6
+ require_relative "matchers/within_depth_matcher"
7
+ require_relative "depth_manager"
8
+ require_relative "trace_stats"
9
+
10
+ module TraceViz
11
+ module Collectors
12
+ class TracePointCollector < BaseCollector
13
+ def initialize
14
+ super()
15
+
16
+ @action_matcher = Matchers::TracePointActionMatcher.new
17
+ @within_depth_matcher = Matchers::WithinDepthMatcher.new
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :action_matcher, :within_depth_matcher
23
+
24
+ def collectible?(trace_point)
25
+ within_depth? || match_action?(trace_point)
26
+ end
27
+
28
+ def build_trace(trace_point)
29
+ TraceData::TracePointBuilder.build(trace_point)
30
+ end
31
+
32
+ def update_trace_depth(trace_data)
33
+ depth_manager.align(trace_data)
34
+ end
35
+
36
+ def match_action?(trace_point)
37
+ action_matcher.matches?(trace_point)
38
+ end
39
+
40
+ def within_depth?
41
+ depth = tracker.current_depth
42
+
43
+ within_depth_matcher.matches?(depth)
44
+ end
45
+
46
+ def depth_manager
47
+ @depth_manager ||= DepthManager.new
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TraceViz
4
+ module Collectors
5
+ class TraceStats
6
+ attr_reader :total_traces, :max_depth, :event_counts
7
+
8
+ def initialize
9
+ @total_traces = 0
10
+ @max_depth = 0
11
+ @event_counts = Hash.new(0)
12
+ end
13
+
14
+ def update(trace_data)
15
+ @total_traces += 1
16
+ @max_depth = [@max_depth, trace_data.depth].max
17
+ @event_counts[trace_data.event] += 1
18
+ end
19
+ end
20
+ end
21
+ end