stack_trace 0.2.1 → 0.3.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 +127 -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 +28 -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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 625635fd7b7003444962cd51a8baa282a8ce298db85ac3cecf46446008ea1da6
4
- data.tar.gz: 660c040d48c94523ffe0e91c689a444cf6c4ea1bc04f7a86f5fe0e899427b947
3
+ metadata.gz: 62cea37e30a1a5cddfef34c91b25a5411b4a5edc017743179f4097a2a9682c43
4
+ data.tar.gz: c06b33ab71d5c66dd4593952201eddbdfc85fec53fde5f321fc1d9a563d3f54e
5
5
  SHA512:
6
- metadata.gz: 75d732bff4f5ee026501386afae896884f3a4939e91270aae06a45429b18550168a1d42c4088f51da64a2079dfca8f18c622d8d9db5c8e3b35e1493dcc649f39
7
- data.tar.gz: 0f8a7d96cdeba0a942439553ee3e71c2864f25abd0fa95353be6726e7697344990d339ffff506a1dc0f8dad7f617a707f5e216642225a0a4d4f41e05c7984a5b
6
+ metadata.gz: e1f0daca22d85120157d4252b7a63d0035a882bad2f3f4b14312734ca65af30d9c8b2c0f6057d573bb27d4ab3494b19e333c090230ec2d39da4b0743b7bd6d4a
7
+ data.tar.gz: 33500c08305ce31b29049e3bab8fbcefbbc5a1a60ce4dd08ba0bd65efd23a7da9bbbf169993908e6b7e67d970db99fd2bd8aad9c67cbab6a2eaf84df6ae0ee99
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 3.0.4
@@ -0,0 +1,84 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
6
+
7
+ We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
8
+
9
+ ## Our Standards
10
+
11
+ Examples of behavior that contributes to a positive environment for our community include:
12
+
13
+ * Demonstrating empathy and kindness toward other people
14
+ * Being respectful of differing opinions, viewpoints, and experiences
15
+ * Giving and gracefully accepting constructive feedback
16
+ * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
17
+ * Focusing on what is best not just for us as individuals, but for the overall community
18
+
19
+ Examples of unacceptable behavior include:
20
+
21
+ * The use of sexualized language or imagery, and sexual attention or
22
+ advances of any kind
23
+ * Trolling, insulting or derogatory comments, and personal or political attacks
24
+ * Public or private harassment
25
+ * Publishing others' private information, such as a physical or email
26
+ address, without their explicit permission
27
+ * Other conduct which could reasonably be considered inappropriate in a
28
+ professional setting
29
+
30
+ ## Enforcement Responsibilities
31
+
32
+ Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
33
+
34
+ Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
35
+
36
+ ## Scope
37
+
38
+ This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
39
+
40
+ ## Enforcement
41
+
42
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at mehmetemininac@gmail.com. All complaints will be reviewed and investigated promptly and fairly.
43
+
44
+ All community leaders are obligated to respect the privacy and security of the reporter of any incident.
45
+
46
+ ## Enforcement Guidelines
47
+
48
+ Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
49
+
50
+ ### 1. Correction
51
+
52
+ **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
53
+
54
+ **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
55
+
56
+ ### 2. Warning
57
+
58
+ **Community Impact**: A violation through a single incident or series of actions.
59
+
60
+ **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
61
+
62
+ ### 3. Temporary Ban
63
+
64
+ **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
65
+
66
+ **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
67
+
68
+ ### 4. Permanent Ban
69
+
70
+ **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
71
+
72
+ **Consequence**: A permanent ban from any sort of public interaction within the community.
73
+
74
+ ## Attribution
75
+
76
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0,
77
+ available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
78
+
79
+ Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
80
+
81
+ [homepage]: https://www.contributor-covenant.org
82
+
83
+ For answers to common questions about this code of conduct, see the FAQ at
84
+ https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
data/Gemfile CHANGED
@@ -1,4 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source "https://rubygems.org"
2
4
 
3
- # Specify your gem's dependencies in stack_trace.gemspec
4
5
  gemspec
6
+
7
+ gem "rake", "~> 13.0"
8
+ gem "rake-compiler"
9
+ gem "rspec", "~> 3.0"
data/Gemfile.lock CHANGED
@@ -1,41 +1,37 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- stack_trace (0.2.1)
4
+ stack_trace (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- coderay (1.1.2)
10
- diff-lcs (1.3)
11
- method_source (0.9.2)
12
- pry (0.12.2)
13
- coderay (~> 1.1.0)
14
- method_source (~> 0.9.0)
15
- rake (13.0.1)
16
- rspec (3.8.0)
17
- rspec-core (~> 3.8.0)
18
- rspec-expectations (~> 3.8.0)
19
- rspec-mocks (~> 3.8.0)
20
- rspec-core (3.8.2)
21
- rspec-support (~> 3.8.0)
22
- rspec-expectations (3.8.4)
9
+ diff-lcs (1.5.0)
10
+ rake (13.0.6)
11
+ rake-compiler (1.2.1)
12
+ rake
13
+ rspec (3.12.0)
14
+ rspec-core (~> 3.12.0)
15
+ rspec-expectations (~> 3.12.0)
16
+ rspec-mocks (~> 3.12.0)
17
+ rspec-core (3.12.1)
18
+ rspec-support (~> 3.12.0)
19
+ rspec-expectations (3.12.2)
23
20
  diff-lcs (>= 1.2.0, < 2.0)
24
- rspec-support (~> 3.8.0)
25
- rspec-mocks (3.8.1)
21
+ rspec-support (~> 3.12.0)
22
+ rspec-mocks (3.12.5)
26
23
  diff-lcs (>= 1.2.0, < 2.0)
27
- rspec-support (~> 3.8.0)
28
- rspec-support (3.8.2)
24
+ rspec-support (~> 3.12.0)
25
+ rspec-support (3.12.0)
29
26
 
30
27
  PLATFORMS
31
- ruby
28
+ arm64-darwin-21
32
29
 
33
30
  DEPENDENCIES
34
- bundler (~> 2.0)
35
- pry
36
31
  rake (~> 13.0)
32
+ rake-compiler
37
33
  rspec (~> 3.0)
38
34
  stack_trace!
39
35
 
40
36
  BUNDLED WITH
41
- 2.1.4
37
+ 2.2.33
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2020 Mehmet Emin INAC
3
+ Copyright (c) 2023 Mehmet Emin INAC
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,214 +1,38 @@
1
1
  # StackTrace
2
2
 
3
- StackTrace traces method calls in your application which can give you an overview about how your application works, which objects depends on which ones and what are the bottlenecks.
3
+ Creates call stack trace for given block of Ruby code.
4
4
 
5
5
  ## Installation
6
6
 
7
- Add this line to your application's Gemfile:
7
+ Install the gem and add to the application's Gemfile by executing:
8
8
 
9
- ```ruby
10
- gem 'stack_trace'
11
- ```
12
-
13
- And then execute:
14
-
15
- $ bundle
9
+ $ bundle add stack_trace
16
10
 
17
- Or install it yourself as:
11
+ If bundler is not being used to manage dependencies, install the gem by executing:
18
12
 
19
13
  $ gem install stack_trace
20
14
 
21
- ## Terminology
22
-
23
- Before we jump into details we should talk about the two important terms that you should grasp first to understand the tracing output, which are `trace` and `span`.
24
-
25
- #### Trace
26
-
27
- Trace is an object which encapsulates the whole process. Whenever you start tracing, there will be a `trace` object associated which has a unique identifier(uuid v4) and holds all the `spans`.
28
-
29
- #### Span
30
-
31
- Span holds the information about the actual **unit of work**. StackTrace will create a new span for each method call if it's been told to do so by the configuration. Spans hold all the information that you need about the method calls like the time taken, arguments etc. as well as the child spans if the method calls othre methods.
32
- You will see detailed information about the spans in the `Getting tracing information` chapter.
33
-
34
15
  ## Usage
35
16
 
36
- Using StackTrace gem is pretty straight forward. First you should configure it to set which modules/classes and which methods should be traced and then you can start tracing the execution of your code with `StackTrace::trace` method.
37
-
38
- #### Configuration
39
-
40
- With the belove configuration, StackTrace will trace all the methods of **Foo** `module/class` and only the `zoo` method of **Bar** `module/class`.
41
-
42
- ```ruby
43
- StackTrace.configure do |config|
44
- config.enabled = true
45
- config.modules = {
46
- Foo => {
47
- instance_methods: :all,
48
- class_methods: :all
49
- },
50
- Bar => { instance_methods: [:zoo] }
51
- }
52
- end
53
- ```
54
-
55
- `instance_methods` and `class_methods` can be configured with the following values;
56
-
57
- - `:all` to trace all methods
58
- - `:skip_inherited` to trace only the methods defined in module/class
59
- - `:path` to trace all the classes/modules defined in a specific path regex(Make sure that StackTrace gem is loaded into memory before any files to use this configuration)
60
- - Array of symbols to specify method names one by one
61
- - Regular expression to trace all methods with matching method names
62
-
63
- Also the keys for `modules` hash can have the following values;
64
-
65
- - `Class/Module` to trace methods of given value
66
- - An array of `Class/Module` to trace methods of all given values
67
- - Regular expression to trace methods of all matching modules or classes.
68
- - { inherits: Class } to trace methods of all classes inherited from base class.
69
-
70
- Here are the example usages;
71
-
72
- ```ruby
73
- StackTrace.configure do |config|
74
- config.enabled = true
75
- config.modules = {
76
- Foo => { instance_methods: :skip_inherited },
77
- [Too, Joo] => { class_methods: :all }
78
- /Ba.*/ => { instance_methods: :all },
79
- { inherits: Zoo } => { instance_methods: [:foo, :bar, :zoo] }
80
- }
81
- end
82
- ```
83
-
84
- #### Tracing
85
-
86
- After configuring the StackTrace, you can call `StackTrace::trace` method to create a tracing information of the code execution as shown below;
87
-
88
17
  ```ruby
89
18
  StackTrace.trace do
90
- foo = Foo.new
91
- foo.do_something
92
- end
93
- ```
94
-
95
- #### Getting tracing information
96
-
97
- Currently StackTrace gem provides tracing information as a Ruby `Hash` object. You can use `StackTrace::Trace::as_json` method to receive the `Hash` for the current trace like so;
19
+ Foo.bar
20
+ end
98
21
 
99
- ```ruby
100
- StackTrace.trace do
101
- # Do something usefull
102
- StackTrace::Trace.as_json
103
- end
22
+ StackTrace.current # => Returns a Hash that contains all the method calls and exception information.
104
23
  ```
105
24
 
106
- #### What does StackTrace collect?
107
-
108
- The `Hash` object returned by `StackTrace::Trace::as_json` method has the following structure;
109
-
110
- * **uuid**: This is a UUID V4 value to identify the trace.
111
- * **spans**: This is an array of spans which has the following structure;
112
- * **receiver**: The identifier for the receiver object.
113
- * **method_name**: The name of the method which this span is created for.
114
- * **arguments**: Arguments received by the method.
115
- * **value**: The return value of the method.
116
- * **exception**: The exception information if an exception is raised in this method. This attribute has the following child attributes:
117
- * **message**: The error message(`error.message`).
118
- * **backtrace**: The backtrace information of the excption as an array of strings.
119
- * **time**: How long the execution of this unit of work took.
120
- * **spans**: Child spans of the span.
121
-
122
- Imagine you have the following configuration and class;
25
+ ## Configuration
123
26
 
124
27
  ```ruby
125
- class Greeting
126
- def hello(first_name, last_name)
127
- "Hello, #{capitalize(first_name)} #{capitalize(last_name)}"
128
- end
129
-
130
- def capitalize(string)
131
- string.capitalize
132
- end
133
- end
134
-
135
28
  StackTrace.configure do |config|
136
- config.enabled = true
137
- config.modules = {
138
- Greeting => { instance_methods: :all }
139
- }
140
- end
141
- ```
29
+ config.trace_ruby = true
30
+ config.trace_c = true
31
+ config.inspect_return_values = true # Default `false` for performance reasons
32
+ config.inspect_arguments = true # Default `false` for performance reasons
142
33
 
143
- The the execution of the following code leads to below return object from `StackTrace::Trace.as_json` method;
144
-
145
- ```ruby
146
- StackTrace.trace do
147
- Greeting.new.hello("john", "doe")
148
- result = StackTrace::Trace.as_json
34
+ config.check_proc = -> (klass_name, method_name) do # If you want to limit the tracing for a set of classes
35
+ klass_name == "Bar"
36
+ end
149
37
  end
150
-
151
- result == {
152
- uuid: "12e2a347-8d5a-4d1d-a5ad-efe012ffcdf9",
153
- spans: [
154
- {
155
- receiver: "Greeting#123124312",
156
- method_name: "initialize",
157
- arguments: {},
158
- value: nil,
159
- exception: nil,
160
- time: "10.927719116210938 µs",
161
- spans: []
162
- },
163
- {
164
- receiver: "Greeting#123124312",
165
- method_name: "hello",
166
- arguments: {
167
- first_name: "john",
168
- last_name: "doe"
169
- },
170
- value: "Hello, John Doe",
171
- exception: nil,
172
- time: "20.831909134113330 µs",
173
- spans: [
174
- {
175
- receiver: "Greeting#123124312",
176
- method_name: "capitalize",
177
- arguments: {
178
- string: "john"
179
- },
180
- value: "John",
181
- exception: nil,
182
- time: "6.198883056640625 µs",
183
- spans: []
184
- },
185
- {
186
- receiver: "Greeting#123124312",
187
- method_name: "capitalize",
188
- arguments: {
189
- string: "doe"
190
- },
191
- value: "Doe",
192
- exception: nil,
193
- time: "4.291534423828125 µs",
194
- spans: []
195
- }
196
- ]
197
- }
198
- ]
199
- }
200
38
  ```
201
-
202
- ## Development
203
-
204
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
205
-
206
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
207
-
208
- ## Contributing
209
-
210
- Bug reports and pull requests are welcome on GitHub at https://github.com/meinac/stack_trace.
211
-
212
- ## License
213
-
214
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -1,6 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
4
  require "rspec/core/rake_task"
5
+ require "rake/extensiontask"
3
6
 
4
7
  RSpec::Core::RakeTask.new(:spec)
5
8
 
6
- task :default => :spec
9
+ task default: :spec
10
+
11
+ Rake::ExtensionTask.new "stack_trace" do |ext|
12
+ ext.lib_dir = "lib/stack_trace/ext"
13
+ end
@@ -0,0 +1,23 @@
1
+ #include <ruby.h>
2
+
3
+ static VALUE inspect_return_values = Qfalse;
4
+ static VALUE inspect_arguments = Qfalse;
5
+
6
+ // We are setting this static variable to gain some performance.
7
+ // Otherwise each time we need this, we would need to get the constant
8
+ // and make method calls.
9
+ VALUE rb_set_inspect_return_values(VALUE self, VALUE val) {
10
+ return inspect_return_values = val;
11
+ }
12
+
13
+ VALUE get_inspect_return_values() {
14
+ return inspect_return_values;
15
+ }
16
+
17
+ VALUE rb_set_inspect_arguments(VALUE self, VALUE val) {
18
+ return inspect_arguments = val;
19
+ }
20
+
21
+ VALUE get_inspect_arguments() {
22
+ return inspect_arguments;
23
+ }
@@ -0,0 +1,6 @@
1
+ #include <ruby.h>
2
+
3
+ VALUE rb_set_inspect_return_values(VALUE self, VALUE val);
4
+ VALUE get_inspect_return_values();
5
+ VALUE rb_set_inspect_arguments(VALUE self, VALUE val);
6
+ VALUE get_inspect_arguments();
@@ -0,0 +1,43 @@
1
+ #include "current_trace.h"
2
+ #include "event_store.h"
3
+ #include "types/event.h"
4
+
5
+ static __thread Trace *current_trace = NULL;
6
+
7
+ Trace *get_current_trace() {
8
+ return current_trace;
9
+ }
10
+
11
+ VALUE rb_create_trace(VALUE _self) {
12
+ if(current_trace != NULL) {
13
+ current_trace->active = false;
14
+
15
+ Event event = {};
16
+ event.trace = current_trace;
17
+ event.event = END_OF_OBSOLOTE_TRACE_EVENT;
18
+
19
+ produce_event(event); // This will tell sidecar to free the memory
20
+ }
21
+
22
+ Span *span = malloc(sizeof(Span));
23
+ span->children_count = 0;
24
+ span->caller = NULL;
25
+
26
+ current_trace = malloc(sizeof(Trace));
27
+ current_trace->finished = false;
28
+ current_trace->top_span = span;
29
+ current_trace->current_span = span;
30
+ current_trace->active = true;
31
+
32
+ return Qtrue;
33
+ }
34
+
35
+ VALUE rb_send_eot(VALUE _self) {
36
+ Event event = {};
37
+ event.trace = current_trace;
38
+ event.event = END_OF_TRACE;
39
+
40
+ produce_event(event);
41
+
42
+ return Qtrue;
43
+ }
@@ -0,0 +1,7 @@
1
+ #include <ruby.h>
2
+
3
+ #include "types/trace.h"
4
+
5
+ Trace *get_current_trace(void);
6
+ VALUE rb_create_trace(VALUE _self);
7
+ VALUE rb_send_eot(VALUE _self);
@@ -0,0 +1,43 @@
1
+ #include <ruby.h>
2
+
3
+ #include "debug.h"
4
+
5
+ void serialize_event(char *buffer, Event *event) {
6
+ switch(event->event) {
7
+ case END_OF_TRACE:
8
+ sprintf(buffer, "End of trace");
9
+ return;
10
+ case END_OF_OBSOLOTE_TRACE_EVENT:
11
+ sprintf(buffer, "End of obsolote trace");
12
+ return;
13
+ case NOOP_EVENT:
14
+ sprintf(buffer, "NO-OP event");
15
+ return;
16
+ }
17
+
18
+ VALUE klass_name = rb_funcall(event->klass, rb_intern("name"), 0);
19
+ VALUE self_name = rb_funcall(event->self_klass, rb_intern("name"), 0);
20
+ VALUE method_name = rb_funcall(event->method, rb_intern("name"), 0);
21
+
22
+ char *klass_name_str = RSTRING_PTR(klass_name);
23
+ char *self_name_str = RSTRING_PTR(self_name);
24
+ char *method_name_str = RSTRING_PTR(method_name);
25
+
26
+ sprintf(
27
+ buffer,
28
+ "klass: %s, "
29
+ "self: %s, "
30
+ "method: %s, "
31
+ "event: %d, "
32
+ "for_singleton: %d",
33
+ klass_name_str,
34
+ self_name_str,
35
+ method_name_str,
36
+ event->event,
37
+ event->for_singleton
38
+ );
39
+ }
40
+
41
+ void serialize_unknown(char *buffer, void *var) {
42
+ sprintf(buffer, "Address: %p", var);
43
+ }
@@ -0,0 +1,37 @@
1
+ #include "types/event.h"
2
+
3
+ #ifdef ST_DEBUG
4
+ void serialize_event(char *buffer, Event *event);
5
+ void serialize_unknown(char *buffer, void *var);
6
+
7
+ static FILE *debug_fp = NULL;
8
+
9
+ #define OPEN_DEBUG_FILE() if(!debug_fp) debug_fp = fopen("debug.log", "a")
10
+
11
+ #define SERIALIZE_STRUCT(s, buffer) \
12
+ _Generic((s), \
13
+ Event*: serialize_event, \
14
+ default: serialize_unknown \
15
+ )(buffer, s)
16
+
17
+ #define DEBUG(msg, s) \
18
+ do { \
19
+ OPEN_DEBUG_FILE(); \
20
+ char buffer[512]; \
21
+ SERIALIZE_STRUCT(s, buffer); \
22
+ fprintf(debug_fp, "DEBUG: %s:%d:%s(): " msg "{ %s }\n", \
23
+ __FILE__, __LINE__, __func__, buffer); \
24
+ fflush(debug_fp); \
25
+ } while(0)
26
+
27
+ #define DEBUG_TEXT(msg, ...) \
28
+ do { \
29
+ OPEN_DEBUG_FILE(); \
30
+ fprintf(debug_fp, "DEBUG: %s:%d:%s(): " msg "\n", \
31
+ __FILE__, __LINE__, __func__, ##__VA_ARGS__); \
32
+ fflush(debug_fp); \
33
+ } while(0)
34
+ #else
35
+ #define DEBUG(msg, ...)
36
+ #define DEBUG_TEXT(msg, ...)
37
+ #endif
@@ -0,0 +1,65 @@
1
+ #include <ruby.h>
2
+ #include <ruby/debug.h>
3
+
4
+ #include "types/event.h"
5
+ #include "event_store.h"
6
+ #include "current_trace.h"
7
+ #include "utils.h"
8
+ #include "configuration.h"
9
+
10
+ VALUE extract_arguments(VALUE tp_val) {
11
+ VALUE main_module = rb_const_get(rb_cObject, rb_intern("StackTrace"));
12
+ VALUE extractor_class = rb_const_get(main_module, rb_intern("ArgumentExtractor"));
13
+
14
+ VALUE arguments = rb_funcall(extractor_class, rb_intern("extract"), 1, tp_val);
15
+ rb_gc_register_address(&arguments);
16
+
17
+ return arguments;
18
+ }
19
+
20
+ void create_event(VALUE tp_val, void *_data) {
21
+ Event event = {};
22
+ int for_singleton = false;
23
+
24
+ rb_trace_arg_t *trace_arg = rb_tracearg_from_tracepoint(tp_val);
25
+
26
+ VALUE klass = rb_tracearg_defined_class(trace_arg);
27
+ VALUE self = rb_tracearg_self(trace_arg);
28
+ VALUE method = rb_tracearg_method_id(trace_arg);
29
+ VALUE self_klass;
30
+
31
+ if(FL_TEST(klass, FL_SINGLETON)) {
32
+ klass = rb_ivar_get(klass, rb_intern("__attached__"));
33
+ for_singleton = true;
34
+ self_klass = rb_funcall(self, rb_intern("name"), 0);
35
+ } else {
36
+ VALUE class = rb_funcall(self, rb_intern("class"), 0);
37
+ self_klass = rb_funcall(class, rb_intern("name"), 0);
38
+ }
39
+
40
+ event.trace = get_current_trace();
41
+ event.tp_val = tp_val;
42
+ event.trace_arg = trace_arg;
43
+ event.event = rb_tracearg_event_flag(trace_arg);
44
+ event.klass = klass;
45
+ event.self_klass = self_klass;
46
+ event.receiver = rb_funcall(self, rb_intern("st_name"), 0);
47
+ event.method = method;
48
+ event.for_singleton = for_singleton;
49
+ event.return_value = Qundef;
50
+ event.arguments = Qundef;
51
+ event.at = get_monotonic_m_secs();
52
+
53
+ if(event.event == RUBY_EVENT_RAISE)
54
+ event.raised_exception = rb_tracearg_raised_exception(trace_arg);
55
+
56
+ if(RTEST(get_inspect_arguments()) &&
57
+ (event.event == RUBY_EVENT_CALL || event.event == RUBY_EVENT_C_CALL || event.event == RUBY_EVENT_B_CALL))
58
+ event.arguments = extract_arguments(tp_val);
59
+
60
+ if(RTEST(get_inspect_return_values()) &&
61
+ (event.event == RUBY_EVENT_RETURN || event.event == RUBY_EVENT_C_RETURN || event.event == RUBY_EVENT_B_RETURN))
62
+ event.return_value = rb_tracearg_return_value(trace_arg);
63
+
64
+ produce_event(event);
65
+ }
@@ -0,0 +1,3 @@
1
+ #include <ruby.h>
2
+
3
+ void create_event(VALUE tp_val, void *_data);