stack_trace 0.2.1 → 0.4.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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/.tool-versions +1 -0
  3. data/CODE_OF_CONDUCT.md +84 -0
  4. data/Gemfile +6 -1
  5. data/Gemfile.lock +19 -23
  6. data/LICENSE.txt +1 -1
  7. data/README.md +15 -191
  8. data/Rakefile +8 -1
  9. data/ext/stack_trace/configuration.c +23 -0
  10. data/ext/stack_trace/configuration.h +6 -0
  11. data/ext/stack_trace/current_trace.c +43 -0
  12. data/ext/stack_trace/current_trace.h +7 -0
  13. data/ext/stack_trace/debug.c +43 -0
  14. data/ext/stack_trace/debug.h +37 -0
  15. data/ext/stack_trace/event_producer.c +65 -0
  16. data/ext/stack_trace/event_producer.h +3 -0
  17. data/ext/stack_trace/event_store.c +109 -0
  18. data/ext/stack_trace/event_store.h +5 -0
  19. data/ext/stack_trace/extconf.rb +7 -0
  20. data/ext/stack_trace/sidecar.c +77 -0
  21. data/ext/stack_trace/sidecar.h +1 -0
  22. data/ext/stack_trace/span.c +106 -0
  23. data/ext/stack_trace/span.h +9 -0
  24. data/ext/stack_trace/stack_trace.c +54 -0
  25. data/ext/stack_trace/trace.c +132 -0
  26. data/ext/stack_trace/trace.h +8 -0
  27. data/ext/stack_trace/types/event.h +31 -0
  28. data/ext/stack_trace/types/span.h +22 -0
  29. data/ext/stack_trace/types/trace.h +15 -0
  30. data/ext/stack_trace/utils.c +8 -0
  31. data/ext/stack_trace/utils.h +1 -0
  32. data/lib/stack_trace/argument_extractor.rb +22 -0
  33. data/lib/stack_trace/configuration.rb +2 -57
  34. data/lib/stack_trace/patch/class.rb +7 -0
  35. data/lib/stack_trace/patch/false_class.rb +7 -0
  36. data/lib/stack_trace/patch/nil_class.rb +7 -0
  37. data/lib/stack_trace/patch/numeric.rb +7 -0
  38. data/lib/stack_trace/patch/object.rb +7 -0
  39. data/lib/stack_trace/patch/symbol.rb +7 -0
  40. data/lib/stack_trace/patch/true_class.rb +7 -0
  41. data/lib/stack_trace/version.rb +3 -1
  42. data/lib/stack_trace.rb +30 -34
  43. data/stack_trace.gemspec +22 -20
  44. metadata +45 -77
  45. data/.gitignore +0 -11
  46. data/.travis.yml +0 -7
  47. data/bin/console +0 -14
  48. data/bin/setup +0 -8
  49. data/lib/stack_trace/integration/rspec.rb +0 -79
  50. data/lib/stack_trace/module_extensions.rb +0 -13
  51. data/lib/stack_trace/setup.rb +0 -62
  52. data/lib/stack_trace/span.rb +0 -94
  53. data/lib/stack_trace/trace.rb +0 -83
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FalseClass
4
+ def st_name
5
+ self
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class NilClass
4
+ def st_name
5
+ self
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Numeric
4
+ def st_name
5
+ self
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Object
4
+ def st_name
5
+ "#{self.class.name}:#{format('%#016x', (object_id << 1))}>"
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Symbol
4
+ def st_name
5
+ "Symbol:#{to_s}"
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TrueClass
4
+ def st_name
5
+ self
6
+ end
7
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module StackTrace
2
- VERSION = "0.2.1"
4
+ VERSION = "0.4.0"
3
5
  end
data/lib/stack_trace.rb CHANGED
@@ -1,48 +1,44 @@
1
- # frozen-string-literal: true
2
-
3
- require "stack_trace/configuration"
4
- require "stack_trace/module_extensions"
5
- require "stack_trace/setup"
6
- require "stack_trace/span"
7
- require "stack_trace/trace"
8
- require "stack_trace/version"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "stack_trace/version"
4
+ require_relative "stack_trace/configuration"
5
+ require_relative "stack_trace/argument_extractor"
6
+ require_relative "stack_trace/patch/object"
7
+ require_relative "stack_trace/patch/class"
8
+ require_relative "stack_trace/patch/nil_class"
9
+ require_relative "stack_trace/patch/numeric"
10
+ require_relative "stack_trace/patch/false_class"
11
+ require_relative "stack_trace/patch/true_class"
12
+ require_relative "stack_trace/patch/symbol"
13
+ require_relative "stack_trace/ext/stack_trace"
9
14
 
10
15
  module StackTrace
11
- TRACED_EVENTS = %i(call c_call return c_return raise).freeze
12
-
13
16
  class << self
14
- def configure
15
- yield configuration
16
- trace_point.enable
17
- end
17
+ def configure(&block)
18
+ return false if configuration.frozen?
18
19
 
19
- def configuration
20
- @configuration ||= Configuration.new
20
+ block.call(configuration)
21
+
22
+ Sidecar.run
23
+ configuration.freeze
21
24
  end
22
25
 
23
- def trace
24
- return unless block_given?
26
+ def trace(&block)
27
+ return block.call if trace_point.enabled?
25
28
 
26
- Trace.start
27
- yield
28
- end
29
+ start_trace # This creates the wrapper span
29
30
 
30
- def current
31
- Trace.current
32
- end
31
+ trace_point.enable do
32
+ block.call
33
+ end
33
34
 
34
- def as_json
35
- Trace.as_json
35
+ complete_trace
36
36
  end
37
37
 
38
- def trace_point
39
- @trace_point ||= TracePoint.new(*TRACED_EVENTS) { |tp| Trace.track(tp) }
38
+ private
39
+
40
+ def configuration
41
+ @configuration ||= Configuration.new
40
42
  end
41
43
  end
42
44
  end
43
-
44
- TracePoint.new(:class) do |tp|
45
- tp.binding.eval <<~RUBY
46
- self.stack_trace_source_location = __FILE__
47
- RUBY
48
- end.enable
data/stack_trace.gemspec CHANGED
@@ -1,32 +1,34 @@
1
+ # frozen_string_literal: true
1
2
 
2
- lib = File.expand_path("../lib", __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "stack_trace/version"
3
+ require_relative "lib/stack_trace/version"
5
4
 
6
5
  Gem::Specification.new do |spec|
7
- spec.name = "stack_trace"
8
- spec.version = StackTrace::VERSION
9
- spec.authors = ["Mehmet Emin INAC"]
10
- spec.email = ["mehmetemininac@gmail.com"]
6
+ spec.name = "stack_trace"
7
+ spec.version = StackTrace::VERSION
8
+ spec.authors = ["Mehmet Emin INAC"]
9
+ spec.email = ["mehmetemininac@gmail.com"]
11
10
 
12
- spec.summary = "Tracks the execution of methods configured"
13
- spec.description = "This library tracks the execution of methods, their arguments, return values etc."
14
- spec.homepage = "https://github.com/meinac/stack_trace"
15
- spec.license = "MIT"
11
+ spec.summary = "StackTrace"
12
+ spec.description = "StackTrace"
13
+ spec.homepage = "https://github.com/meinac/stack_trace"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 3.0.0"
16
16
 
17
17
  # Specify which files should be added to the gem when it is released.
18
18
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ spec.files = Dir.chdir(__dir__) do
20
+ `git ls-files -z`.split("\x0").reject do |f|
21
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
22
+ end
21
23
  end
22
- spec.bindir = "exe"
23
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.bindir = "exe"
25
+ spec.extensions = %w[ext/stack_trace/extconf.rb]
26
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
24
27
  spec.require_paths = ["lib"]
25
28
 
26
- spec.required_ruby_version = '>= 1.9.2'
29
+ # Uncomment to register a new dependency of your gem
30
+ # spec.add_dependency "example-gem", "~> 1.0"
27
31
 
28
- spec.add_development_dependency "bundler", "~> 2.0"
29
- spec.add_development_dependency "rake", "~> 13.0"
30
- spec.add_development_dependency "rspec", "~> 3.0"
31
- spec.add_development_dependency "pry"
32
+ # For more information and examples about making a new gem, check out our
33
+ # guide at: https://bundler.io/guides/creating_gem.html
32
34
  end
metadata CHANGED
@@ -1,103 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stack_trace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mehmet Emin INAC
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-10-04 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '2.0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '2.0'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '13.0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '13.0'
41
- - !ruby/object:Gem::Dependency
42
- name: rspec
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '3.0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '3.0'
55
- - !ruby/object:Gem::Dependency
56
- name: pry
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- description: This library tracks the execution of methods, their arguments, return
70
- values etc.
11
+ date: 2023-04-06 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: StackTrace
71
14
  email:
72
15
  - mehmetemininac@gmail.com
73
16
  executables: []
74
- extensions: []
17
+ extensions:
18
+ - ext/stack_trace/extconf.rb
75
19
  extra_rdoc_files: []
76
20
  files:
77
- - ".gitignore"
78
21
  - ".rspec"
79
- - ".travis.yml"
22
+ - ".tool-versions"
23
+ - CODE_OF_CONDUCT.md
80
24
  - Gemfile
81
25
  - Gemfile.lock
82
26
  - LICENSE.txt
83
27
  - README.md
84
28
  - Rakefile
85
- - bin/console
86
- - bin/setup
29
+ - ext/stack_trace/configuration.c
30
+ - ext/stack_trace/configuration.h
31
+ - ext/stack_trace/current_trace.c
32
+ - ext/stack_trace/current_trace.h
33
+ - ext/stack_trace/debug.c
34
+ - ext/stack_trace/debug.h
35
+ - ext/stack_trace/event_producer.c
36
+ - ext/stack_trace/event_producer.h
37
+ - ext/stack_trace/event_store.c
38
+ - ext/stack_trace/event_store.h
39
+ - ext/stack_trace/extconf.rb
40
+ - ext/stack_trace/sidecar.c
41
+ - ext/stack_trace/sidecar.h
42
+ - ext/stack_trace/span.c
43
+ - ext/stack_trace/span.h
44
+ - ext/stack_trace/stack_trace.c
45
+ - ext/stack_trace/trace.c
46
+ - ext/stack_trace/trace.h
47
+ - ext/stack_trace/types/event.h
48
+ - ext/stack_trace/types/span.h
49
+ - ext/stack_trace/types/trace.h
50
+ - ext/stack_trace/utils.c
51
+ - ext/stack_trace/utils.h
87
52
  - lib/stack_trace.rb
53
+ - lib/stack_trace/argument_extractor.rb
88
54
  - lib/stack_trace/configuration.rb
89
- - lib/stack_trace/integration/rspec.rb
90
- - lib/stack_trace/module_extensions.rb
91
- - lib/stack_trace/setup.rb
92
- - lib/stack_trace/span.rb
93
- - lib/stack_trace/trace.rb
55
+ - lib/stack_trace/patch/class.rb
56
+ - lib/stack_trace/patch/false_class.rb
57
+ - lib/stack_trace/patch/nil_class.rb
58
+ - lib/stack_trace/patch/numeric.rb
59
+ - lib/stack_trace/patch/object.rb
60
+ - lib/stack_trace/patch/symbol.rb
61
+ - lib/stack_trace/patch/true_class.rb
94
62
  - lib/stack_trace/version.rb
95
63
  - stack_trace.gemspec
96
64
  homepage: https://github.com/meinac/stack_trace
97
65
  licenses:
98
66
  - MIT
99
67
  metadata: {}
100
- post_install_message:
68
+ post_install_message:
101
69
  rdoc_options: []
102
70
  require_paths:
103
71
  - lib
@@ -105,15 +73,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
105
73
  requirements:
106
74
  - - ">="
107
75
  - !ruby/object:Gem::Version
108
- version: 1.9.2
76
+ version: 3.0.0
109
77
  required_rubygems_version: !ruby/object:Gem::Requirement
110
78
  requirements:
111
79
  - - ">="
112
80
  - !ruby/object:Gem::Version
113
81
  version: '0'
114
82
  requirements: []
115
- rubygems_version: 3.0.8
116
- signing_key:
83
+ rubygems_version: 3.2.33
84
+ signing_key:
117
85
  specification_version: 4
118
- summary: Tracks the execution of methods configured
86
+ summary: StackTrace
119
87
  test_files: []
data/.gitignore DELETED
@@ -1,11 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
9
-
10
- # rspec failure tracking
11
- .rspec_status
data/.travis.yml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.6.2
7
- before_install: gem install bundler -v 2.0.1
data/bin/console DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "stack_trace"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start(__FILE__)
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
@@ -1,79 +0,0 @@
1
- # frozen-string-literal: true
2
-
3
- require "json"
4
-
5
- RSpec.configuration.before(:suite) do
6
- StackTrace::Integration::Rspec.create_tracing_directory
7
- end
8
-
9
- RSpec.configuration.after(:suite) do
10
- StackTrace::Integration::Rspec.finish_tracing
11
- end
12
-
13
- RSpec.configuration.around(:each) do |example|
14
- StackTrace.trace do
15
- example.run
16
- StackTrace::Integration::Rspec.save_trace_for(example)
17
- end
18
- end
19
-
20
- module StackTrace
21
- module Integration
22
- class Rspec
23
- EXAMPLE_META_KEYS = %i(file_path line_number scoped_id description full_description)
24
- FINAL_MESSAGE = <<~TEXT
25
- \e[1m
26
- StackTrace:
27
-
28
- Trace information is saved into \e[32m%{file_path}\e[0m
29
- \e[22m
30
- TEXT
31
-
32
- class << self
33
- def create_tracing_directory
34
- Dir.mkdir(tracing_dir_path) unless Dir.exist?(tracing_dir_path)
35
- end
36
-
37
- def finish_tracing
38
- save_examples
39
- print_message
40
- end
41
-
42
- def save_trace_for(example)
43
- examples << example_data(example)
44
- end
45
-
46
- private
47
-
48
- def examples
49
- @examples ||= []
50
- end
51
-
52
- def save_examples
53
- File.write(tracing_file_path, examples.to_json)
54
- end
55
-
56
- def tracing_file_path
57
- File.join(tracing_dir_path, trace_file_name)
58
- end
59
-
60
- def tracing_dir_path
61
- File.expand_path("stack_trace")
62
- end
63
-
64
- def trace_file_name
65
- @trace_file_name ||= Time.now.strftime('%d_%m_%Y %H_%M_%S.json')
66
- end
67
-
68
- def example_data(example)
69
- example.metadata.slice(*EXAMPLE_META_KEYS)
70
- .merge!(trace: Trace.current.as_json)
71
- end
72
-
73
- def print_message
74
- puts format(FINAL_MESSAGE, file_path: tracing_file_path)
75
- end
76
- end
77
- end
78
- end
79
- end
@@ -1,13 +0,0 @@
1
- # frozen-string-literal: true
2
-
3
- module StackTrace
4
- module ModuleExtensions
5
- attr_accessor :stack_trace_source_location
6
-
7
- def trace_method?(method_id)
8
- Setup.trackable?(self, method_id)
9
- end
10
- end
11
- end
12
-
13
- Module.include(StackTrace::ModuleExtensions)
@@ -1,62 +0,0 @@
1
- # frozen-string-literal: true
2
-
3
- module StackTrace
4
- class Setup
5
- class << self
6
- def trackable?(mod, method_id)
7
- store[mod].trace?(method_id)
8
- end
9
-
10
- def store
11
- @store ||= Hash.new do |h, k|
12
- h[k.singleton_class] = new(k, :class_methods)
13
- h[k] = new(k, :instance_methods)
14
- end
15
- end
16
- end
17
-
18
- def initialize(klass, context)
19
- self.klass = klass
20
- self.context = context
21
- end
22
-
23
- def trace?(method_id)
24
- enabled? && traced_method?(method_id)
25
- end
26
-
27
- private
28
-
29
- attr_accessor :klass, :context
30
-
31
- def enabled?
32
- defined?(@enabled) ? @enabled : (@enabled = !config.nil?)
33
- end
34
-
35
- def config
36
- @config ||= StackTrace.configuration.for(klass)
37
- end
38
-
39
- def traced_method?(method_id)
40
- method_lookup[method_id]
41
- end
42
-
43
- def method_lookup
44
- @method_lookup ||= Hash.new { |lookup, method_id| lookup[method_id] = method_enabled?(method_id) }
45
- end
46
-
47
- def method_enabled?(method_id)
48
- case method_config
49
- when Array
50
- method_config.include?(method_id)
51
- when Symbol
52
- method_config != :skip_inherited || instance_methods(false).include?(method_id)
53
- when Regexp
54
- method_id =~ method_config
55
- end
56
- end
57
-
58
- def method_config
59
- @method_config ||= config[1].fetch(context, [])
60
- end
61
- end
62
- end
@@ -1,94 +0,0 @@
1
- # frozen-string-literal: true
2
-
3
- module StackTrace
4
- class Span
5
- class << self
6
- def start_from(trace_point, parent)
7
- new(
8
- receiver(trace_point),
9
- trace_point.method_id,
10
- extract_arguments(trace_point),
11
- parent
12
- )
13
- end
14
-
15
- private
16
-
17
- def receiver(trace_point)
18
- trace_point.binding.eval("self").to_s
19
- end
20
-
21
- def extract_arguments(trace_point)
22
- trace_point.parameters
23
- .map(&:last)
24
- .each_with_object({}) do |parameter, memo|
25
- memo[parameter] = trace_point.binding.eval(parameter.to_s).inspect
26
- end
27
- end
28
- end
29
-
30
- attr_writer :exception
31
-
32
- def initialize(receiver, method_name, args, parent)
33
- self.receiver = receiver
34
- self.method_name = method_name
35
- self.args = args
36
- self.parent = parent
37
- self.started_at = Time.now.to_f
38
- self.spans = []
39
- end
40
-
41
- def <<(span)
42
- (spans << span) && span
43
- end
44
-
45
- def close(trace_point)
46
- self.value = trace_point.return_value.inspect
47
- self.finished_at = Time.now.to_f
48
- parent
49
- end
50
-
51
- def as_json
52
- {
53
- receiver: receiver,
54
- method_name: method_name,
55
- arguments: args,
56
- value: value,
57
- exception: exception_as_json,
58
- time: time,
59
- spans: spans.map(&:as_json)
60
- }
61
- end
62
-
63
- private
64
-
65
- attr_accessor :receiver, :method_name, :args, :value, :parent, :spans, :started_at, :finished_at
66
- attr_reader :exception
67
-
68
- def time
69
- case time_ns
70
- when 0..1_000
71
- "#{time_ns} ns"
72
- when 0..1_000_000
73
- "#{time_ns / 1_000} µs"
74
- when 0..1_000_000_000
75
- "#{time_ns / 1_000_000} ms"
76
- else
77
- "#{time_ns / 1_000_000_000} s"
78
- end
79
- end
80
-
81
- def exception_as_json
82
- return unless exception
83
-
84
- {
85
- message: exception.message,
86
- backtrace: exception.backtrace
87
- }
88
- end
89
-
90
- def time_ns
91
- (finished_at - started_at) * 1_000_000_000
92
- end
93
- end
94
- end