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,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_exporter"
4
+
5
+ module TraceViz
6
+ module Exporters
7
+ class TextExporter < BaseExporter
8
+ private
9
+
10
+ def content
11
+ data.join("\n")
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TraceViz
4
+ module Exporters
5
+ module Transformers
6
+ class BaseTransformer
7
+ def initialize(collector)
8
+ @collector = collector
9
+ end
10
+
11
+ def transform
12
+ raise NotImplementedError
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :collector
18
+
19
+ def collection
20
+ collector.collection
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_transformer"
4
+ require "trace_viz/exporters/formatters/method_call_formatter"
5
+ require "trace_viz/exporters/formatters/method_return_formatter"
6
+
7
+ module TraceViz
8
+ module Exporters
9
+ module Transformers
10
+ class TextTransformer < BaseTransformer
11
+ def transform
12
+ collection.map do |trace_data|
13
+ format_item(trace_data)
14
+ end
15
+ end
16
+
17
+ def format_item(trace_data)
18
+ case trace_data.event
19
+ when :call
20
+ Formatters::MethodCallFormatter.new(trace_data).format
21
+ when :return
22
+ Formatters::MethodReturnFormatter.new(trace_data).format
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "helpers/indent_helper"
4
+ require_relative "helpers/depth_helper"
5
+ require_relative "helpers/time_helper"
6
+ require_relative "helpers/params_helper"
7
+ require_relative "helpers/source_helper"
8
+ require_relative "helpers/result_helper"
9
+ require_relative "helpers/method_details_helper"
10
+
11
+ module TraceViz
12
+ module Formatters
13
+ class BaseFormatter
14
+ #
15
+ # General formatting methods for TraceData::Base
16
+ # These methods are used to format the output of the trace data
17
+ # based on the configuration settings.
18
+ #
19
+
20
+ include Helpers::IndentHelper
21
+ include Helpers::DepthHelper
22
+ include Helpers::TimeHelper
23
+ include Helpers::ParamsHelper
24
+ include Helpers::SourceHelper
25
+ include Helpers::ResultHelper
26
+ include Helpers::MethodDetailsHelper
27
+
28
+ def initialize(trace_data)
29
+ @trace_data = trace_data
30
+ @config = @trace_data.config
31
+ end
32
+
33
+ def format
34
+ raise NotImplementedError
35
+ end
36
+
37
+ private
38
+
39
+ attr_reader :trace_data, :config
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TraceViz
4
+ module Formatters
5
+ module Helpers
6
+ module DepthHelper
7
+ def depth_representation
8
+ return unless config.general[:show_depth]
9
+
10
+ if trace_data.depth.zero?
11
+ "depth[0]"
12
+ elsif trace_data.event == :call
13
+ "depth[#{trace_data.depth}]"
14
+ elsif trace_data.event == :return
15
+ "depth[#{trace_data.depth}]"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TraceViz
4
+ module Formatters
5
+ module Helpers
6
+ module IndentHelper
7
+ def indent_representation
8
+ return unless config.general[:show_indent] && config.general[:show_depth]
9
+
10
+ " " * (config.general[:tab_size] * trace_data.depth)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TraceViz
4
+ module Formatters
5
+ module Helpers
6
+ module MethodDetailsHelper
7
+ def method_name_representation
8
+ return unless config.general[:show_method_name]
9
+
10
+ "#{trace_data.klass}##{trace_data.action}"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "trace_viz/utils/format_utils"
4
+
5
+ module TraceViz
6
+ module Formatters
7
+ module Helpers
8
+ module ParamsHelper
9
+ def params_representation
10
+ return unless config.params[:show]
11
+
12
+ truncated_params = trace_data.params.transform_values do |value|
13
+ Utils::FormatUtils.truncate_value(value, config.params[:truncate_values])
14
+ end
15
+
16
+ formatted_values = Utils::FormatUtils.format_key_value_pairs(
17
+ truncated_params,
18
+ config.params[:mode],
19
+ )
20
+
21
+ "(#{formatted_values})"
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "trace_viz/utils/format_utils"
4
+
5
+ module TraceViz
6
+ module Formatters
7
+ module Helpers
8
+ module ResultHelper
9
+ def result_representation
10
+ return unless config.result[:show]
11
+
12
+ truncated_result = Utils::FormatUtils.truncate_value(
13
+ trace_data.result.inspect,
14
+ config.result[:truncate_length],
15
+ )
16
+ "#=> #{truncated_result}"
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "trace_viz/utils/format_utils"
4
+
5
+ module TraceViz
6
+ module Formatters
7
+ module Helpers
8
+ module SourceHelper
9
+ def source_location_representation
10
+ return unless config.source_location[:show]
11
+
12
+ truncated_path = Utils::FormatUtils.truncate_value(
13
+ trace_data.path,
14
+ config.source_location[:truncate_length],
15
+ )
16
+ "at #{truncated_path}:#{trace_data.line_number}"
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TraceViz
4
+ module Formatters
5
+ module Helpers
6
+ module TimeHelper
7
+ def execution_time_representation
8
+ return unless config.execution[:show_time] && trace_data.duration
9
+
10
+ "in #{trace_data.duration}ms"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -2,72 +2,62 @@
2
2
 
3
3
  module TraceViz
4
4
  class Logger
5
- COLORS = {
6
- reset: "\e[0m",
7
- info: "\e[34m",
8
- success: "\e[32m",
9
- error: "\e[31m",
10
- warn: "\e[33m",
11
- start: "\e[36m",
12
- finish: "\e[35m",
13
- }.freeze
14
-
15
- EMOJIS = {
16
- info: "ℹ️",
17
- success: "✅",
18
- error: "❌",
19
- warn: "⚠️",
20
- start: "🚀",
21
- finish: "🏁",
22
- }.freeze
23
-
24
- LEVELS = [:info, :success, :error, :warn, :start, :finish].freeze
5
+ LEVELS = Defaults.action_colors.keys.freeze
25
6
 
26
7
  def initialize(output: $stdout)
27
8
  @output = output
28
9
  end
29
10
 
30
- def info(message)
31
- log(:info, message)
11
+ LEVELS.each do |level|
12
+ define_method(level) do |message|
13
+ log(message, level)
14
+ end
32
15
  end
33
16
 
34
- def success(message)
35
- log(:success, message)
36
- end
17
+ def log(message, level = :default)
18
+ validate_message!(message)
19
+ validate_level!(level)
37
20
 
38
- def error(message)
39
- log(:error, message)
40
- end
21
+ color = color_for(level)
22
+ emoji = emoji_for(level)
41
23
 
42
- def warn(message)
43
- log(:warn, message)
24
+ raw_message = build_message(message, level, emoji)
25
+ formatted_message = wrap_in_color(raw_message, color)
26
+
27
+ @output.puts(formatted_message)
44
28
  end
45
29
 
46
- def start(message)
47
- log(:start, message)
30
+ private
31
+
32
+ def validate_message!(message)
33
+ raise ArgumentError, "Message must be a String" unless message.is_a?(String)
48
34
  end
49
35
 
50
- def finish(message)
51
- log(:finish, message)
36
+ def validate_level!(level)
37
+ raise ArgumentError, "Invalid log level: #{level}" unless LEVELS.include?(level)
52
38
  end
53
39
 
54
- private
40
+ def color_for(level)
41
+ color_key = Defaults.action_colors.fetch(level)
42
+ Defaults.colors.fetch(color_key)
43
+ end
55
44
 
56
- def log(level, message)
57
- return unless LEVELS.include?(level)
45
+ def default_color
46
+ color_for(:default)
47
+ end
58
48
 
59
- color = COLORS[level] || COLORS[:info]
60
- emoji = EMOJIS[level] || EMOJIS[:info]
49
+ def emoji_for(level)
50
+ Defaults.action_emojis.fetch(level, "")
51
+ end
61
52
 
62
- # Align emoji and level using fixed-width columns
63
- formatted_message = format(
64
- "#{color}%-3s %-8s#{COLORS[:reset]} %s",
65
- emoji,
66
- "[#{level.to_s.upcase}]",
67
- message,
68
- )
53
+ def build_message(message, level, emoji)
54
+ level_str = level == :default ? "" : "[#{level.to_s.upcase}]"
55
+ merged_emoji_level = "#{emoji} #{level_str}".strip
56
+ format("%-12s %s", merged_emoji_level, message)
57
+ end
69
58
 
70
- @output.puts(formatted_message)
59
+ def wrap_in_color(message, color)
60
+ "#{color}#{message}#{default_color}"
71
61
  end
72
62
  end
73
63
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "trace_viz/loggers/trace_formatters/method_call_formatter"
4
+ require "trace_viz/loggers/trace_formatters/method_return_formatter"
5
+
6
+ module TraceViz
7
+ module Loggers
8
+ class TraceBuilder
9
+ FORMATTERS = {
10
+ call: TraceFormatters::MethodCallFormatter,
11
+ return: TraceFormatters::MethodReturnFormatter,
12
+ }.freeze
13
+
14
+ def initialize(trace_data)
15
+ @trace_data = trace_data
16
+ end
17
+
18
+ def build
19
+ formatter_class = FORMATTERS[trace_data.event]
20
+ raise ArgumentError, "No formatter found for #{trace_data.event}" unless formatter_class
21
+
22
+ formatter_class.new(trace_data).format
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :trace_data
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "trace_viz/formatters/base_formatter"
4
+ require "trace_viz/utils/colorize"
5
+
6
+ module TraceViz
7
+ module Loggers
8
+ module TraceFormatters
9
+ class BaseFormatter < TraceViz::Formatters::BaseFormatter
10
+ private
11
+
12
+ def colorize(text, *styles)
13
+ Utils::Colorize.colorize(text, *styles)
14
+ end
15
+
16
+ def formatted_method_name
17
+ return unless config.general[:show_method_name]
18
+
19
+ "#{formatted_class_name}#{formatted_action_name}"
20
+ end
21
+
22
+ def formatted_class_name
23
+ colorize("#{trace_data.klass}#", :bold, :yellow)
24
+ end
25
+
26
+ def formatted_action_name
27
+ colorize(trace_data.action, :light_cyan)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_formatter"
4
+
5
+ module TraceViz
6
+ module Loggers
7
+ module TraceFormatters
8
+ class MethodCallFormatter < BaseFormatter
9
+ def format
10
+ [
11
+ indent_representation,
12
+ colorize(depth_representation, :blue),
13
+ formatted_method_name,
14
+ colorize(source_location_representation, :dark_gray),
15
+ colorize(params_representation, :light_yellow),
16
+ ].compact.join(" ")
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_formatter"
4
+
5
+ module TraceViz
6
+ module Loggers
7
+ module TraceFormatters
8
+ class MethodReturnFormatter < BaseFormatter
9
+ def format
10
+ [
11
+ indent_representation,
12
+ colorize(depth_representation, :blue),
13
+ formatted_method_name,
14
+ colorize(result_representation, :cyan),
15
+ colorize(source_location_representation, :dark_gray),
16
+ colorize(execution_time_representation, :red),
17
+ ].compact.join(" ")
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "trace_builder"
4
+
5
+ module TraceViz
6
+ module Loggers
7
+ class TraceLogger
8
+ LOG_LEVELS = {
9
+ call: :start,
10
+ return: :finish,
11
+ }.freeze
12
+
13
+ class << self
14
+ def log(trace_data)
15
+ new(trace_data).log
16
+ end
17
+ end
18
+
19
+ def initialize(trace_data)
20
+ @logger = TraceViz.logger
21
+ @trace_data = trace_data
22
+ end
23
+
24
+ def log
25
+ log_level = LOG_LEVELS[trace_data.event] || :info
26
+ logger.send(log_level, formatted_message)
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :logger, :trace_data
32
+
33
+ def formatted_message
34
+ Loggers::TraceBuilder.new(trace_data).build
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "trace_builder"
4
+
5
+ module TraceViz
6
+ module Loggers
7
+ class TraceStatsLogger
8
+ class << self
9
+ def log(collector)
10
+ new(collector).log
11
+ end
12
+ end
13
+
14
+ def initialize(collector)
15
+ @logger = TraceViz.logger
16
+ @stats = collector.stats
17
+ end
18
+
19
+ def log
20
+ logger.stats(formatted_stats)
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :logger, :stats
26
+
27
+ def formatted_stats
28
+ event_counts = stats.event_counts.map { |event, count| "#{event.capitalize}: #{count}" }.join(", ")
29
+ "Total Traces: #{stats.total_traces} | Max Depth: #{stats.max_depth} | Event Counts: [#{event_counts}]"
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "trace_viz/context"
4
+
5
+ module TraceViz
6
+ module TraceData
7
+ class Base
8
+ attr_reader :config,
9
+ :timestamp
10
+ attr_accessor :depth
11
+
12
+ def initialize
13
+ @config = Context.for(:config).configuration
14
+
15
+ @depth = 0
16
+ record_timestamp
17
+ end
18
+
19
+ # Unique ID for each individual event
20
+ def id
21
+ raise NotImplementedError
22
+ end
23
+
24
+ # Shared ID betweem events for the same method call
25
+ def action_id
26
+ raise NotImplementedError
27
+ end
28
+
29
+ def action
30
+ raise NotImplementedError
31
+ end
32
+
33
+ def event
34
+ raise NotImplementedError
35
+ end
36
+
37
+ def path
38
+ raise NotImplementedError
39
+ end
40
+
41
+ def line_number
42
+ raise NotImplementedError
43
+ end
44
+
45
+ def klass
46
+ raise NotImplementedError
47
+ end
48
+
49
+ private
50
+
51
+ def record_timestamp
52
+ @timestamp = Time.now
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../base"
4
+
5
+ module TraceViz
6
+ module TraceData
7
+ module TracePoint
8
+ class Base < TraceData::Base
9
+ attr_reader :trace_point,
10
+ :id,
11
+ :action_id,
12
+ :event,
13
+ :klass,
14
+ :action,
15
+ :path,
16
+ :line_number
17
+
18
+ def initialize(trace_point)
19
+ super()
20
+
21
+ @trace_point = trace_point
22
+
23
+ populate_trace_attributes
24
+ assign_ids
25
+ end
26
+
27
+ def duration
28
+ # TODO: Implement duration calculation
29
+ end
30
+
31
+ private
32
+
33
+ def populate_trace_attributes
34
+ @event = trace_point.event
35
+ @klass = trace_point.defined_class
36
+ @action = trace_point.callee_id
37
+ @path = trace_point.path
38
+ @line_number = trace_point.lineno
39
+ end
40
+
41
+ def assign_ids
42
+ @id = generate_unique_id
43
+ @action_id = generate_action_id
44
+ end
45
+
46
+ def memory_id
47
+ trace_point.self.object_id
48
+ end
49
+
50
+ def generate_unique_id
51
+ [
52
+ memory_id,
53
+ action,
54
+ path,
55
+ line_number,
56
+ ].join("_")
57
+ end
58
+
59
+ def generate_action_id
60
+ [
61
+ memory_id,
62
+ action,
63
+ ].join("_")
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end