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.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +34 -0
- data/README.md +130 -38
- data/examples/example.cast +285 -0
- data/examples/example.rb +94 -23
- data/lib/trace_viz/adapters/base_adapter.rb +0 -2
- data/lib/trace_viz/adapters/trace_point_adapter.rb +17 -11
- data/lib/trace_viz/collectors/base_collector.rb +83 -0
- data/lib/trace_viz/collectors/depth_manager.rb +37 -0
- data/lib/trace_viz/collectors/evaluators/base_evaluator.rb +23 -0
- data/lib/trace_viz/collectors/evaluators/filter_evaluator.rb +30 -0
- data/lib/trace_viz/collectors/evaluators/hidden_evaluator.rb +21 -0
- data/lib/trace_viz/collectors/filters/base_filter.rb +23 -0
- data/lib/trace_viz/collectors/filters/exclude_classes_filter.rb +28 -0
- data/lib/trace_viz/collectors/filters/exclude_default_classes_filter.rb +38 -0
- data/lib/trace_viz/collectors/filters/exclude_gems_filter.rb +30 -0
- data/lib/trace_viz/collectors/filters/exclude_internal_call_filter.rb +31 -0
- data/lib/trace_viz/collectors/filters/exclude_rails_framework_filter.rb +38 -0
- data/lib/trace_viz/collectors/filters/include_classes_filter.rb +28 -0
- data/lib/trace_viz/collectors/filters/include_gems_filter.rb +54 -0
- data/lib/trace_viz/collectors/filters/registry.rb +59 -0
- data/lib/trace_viz/collectors/matchers/trace_point_action_matcher.rb +36 -0
- data/lib/trace_viz/collectors/matchers/within_depth_matcher.rb +25 -0
- data/lib/trace_viz/collectors/trace_point_collector.rb +51 -0
- data/lib/trace_viz/collectors/trace_stats.rb +21 -0
- data/lib/trace_viz/config/copier.rb +38 -0
- data/lib/trace_viz/config/validator.rb +74 -0
- data/lib/trace_viz/configuration.rb +36 -30
- data/lib/trace_viz/context/config_context.rb +1 -1
- data/lib/trace_viz/context/manager.rb +17 -21
- data/lib/trace_viz/context/map.rb +29 -0
- data/lib/trace_viz/context/registry.rb +37 -0
- data/lib/trace_viz/context/tracking/active_calls.rb +37 -0
- data/lib/trace_viz/context/tracking_context.rb +7 -2
- data/lib/trace_viz/context.rb +2 -2
- data/lib/trace_viz/core/tracer.rb +1 -0
- data/lib/trace_viz/defaults.rb +139 -0
- data/lib/trace_viz/exporters/base_exporter.rb +84 -0
- data/lib/trace_viz/exporters/formatters/base_formatter.rb +12 -0
- data/lib/trace_viz/exporters/formatters/method_call_formatter.rb +21 -0
- data/lib/trace_viz/exporters/formatters/method_return_formatter.rb +22 -0
- data/lib/trace_viz/exporters/text_exporter.rb +15 -0
- data/lib/trace_viz/exporters/transformers/base_transformer.rb +25 -0
- data/lib/trace_viz/exporters/transformers/text_transformer.rb +28 -0
- data/lib/trace_viz/formatters/base_formatter.rb +42 -0
- data/lib/trace_viz/formatters/helpers/depth_helper.rb +21 -0
- data/lib/trace_viz/formatters/helpers/indent_helper.rb +15 -0
- data/lib/trace_viz/formatters/helpers/method_details_helper.rb +15 -0
- data/lib/trace_viz/formatters/helpers/params_helper.rb +26 -0
- data/lib/trace_viz/formatters/helpers/result_helper.rb +21 -0
- data/lib/trace_viz/formatters/helpers/source_helper.rb +21 -0
- data/lib/trace_viz/formatters/helpers/time_helper.rb +15 -0
- data/lib/trace_viz/logger.rb +37 -47
- data/lib/trace_viz/loggers/trace_builder.rb +30 -0
- data/lib/trace_viz/loggers/trace_formatters/base_formatter.rb +32 -0
- data/lib/trace_viz/loggers/trace_formatters/method_call_formatter.rb +21 -0
- data/lib/trace_viz/loggers/trace_formatters/method_return_formatter.rb +22 -0
- data/lib/trace_viz/loggers/trace_logger.rb +38 -0
- data/lib/trace_viz/loggers/trace_stats_logger.rb +33 -0
- data/lib/trace_viz/trace_data/base.rb +56 -0
- data/lib/trace_viz/trace_data/trace_point/base.rb +68 -0
- data/lib/trace_viz/trace_data/trace_point/method_call.rb +42 -0
- data/lib/trace_viz/trace_data/trace_point/method_return.rb +25 -0
- data/lib/trace_viz/trace_data/trace_point_builder.rb +23 -0
- data/lib/trace_viz/utils/colorize.rb +12 -23
- data/lib/trace_viz/utils/format_utils.rb +67 -0
- data/lib/trace_viz/version.rb +1 -1
- metadata +58 -13
- data/lib/trace_viz/adapters/trace_point/depth_manager.rb +0 -34
- data/lib/trace_viz/adapters/trace_point/event_handler.rb +0 -36
- data/lib/trace_viz/adapters/trace_point/trace_data.rb +0 -89
- data/lib/trace_viz/adapters/trace_point/trace_formatter.rb +0 -95
- data/lib/trace_viz/adapters/trace_point/trace_logger.rb +0 -44
- data/lib/trace_viz/context/manager/context_map.rb +0 -31
- data/lib/trace_viz/context/manager/context_operations.rb +0 -60
- data/lib/trace_viz/context/manager/context_registry.rb +0 -20
- 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
|