stack_trace 0.2.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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