stack_trace 0.4.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ac9e909692657f9e1b0cd9fc6475faf494458954513aa2e659e9faeacfb3d51b
4
- data.tar.gz: d4819f5e40ef2d81cc5cc539247916ed16416eed9400f63007fe85edc8c9c4cf
3
+ metadata.gz: a44fbab04e5a7a787dd995fbee5ea3e503080172df937a91e122728eb4884744
4
+ data.tar.gz: c004c70f42efc53e0776520d9e39a902346015eca012614913dd9a04e9822344
5
5
  SHA512:
6
- metadata.gz: 072443043f5910dfd02ded927653a23abacefede4f17fd87155521275818b0b90aa769544c30e9f06b5c46c24193e9bac12f711ae39c4f887340d435402f40c2
7
- data.tar.gz: d3a5c0ae3803776ea0ad504c825c75ca0d9a70d5153a22133f809633631f824a7540fe7dd72c76c9e4eece214bb578d04765445f39089adadc6076abbe7af10a
6
+ metadata.gz: aab482726e6436266555c91fbd51a0b44d8b5d0b6b0f3e72cd11448eaac96ea0d49582df77ab828cbbd38be93d177214cddb50a606ad8e899bb541179c43ed0f
7
+ data.tar.gz: 4e57a54efcb00a4a2701a5169130642be00fcd1aff13c4d508b0ac663f933fa5443eceffc78d74199d0fcf2ced21054559eabe85675ec2190b2f8ec768a02dc3
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- stack_trace (0.4.0)
4
+ stack_trace (0.6.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -0,0 +1,11 @@
1
+ #include "argument.h"
2
+
3
+ void free_arguments(Argument *arguments, int count) {
4
+ int i;
5
+
6
+ for(i = 0; i < count; i++) {
7
+ free(arguments[i].value);
8
+ }
9
+
10
+ free(arguments);
11
+ }
@@ -0,0 +1,3 @@
1
+ #include "types/argument.h"
2
+
3
+ void free_arguments(Argument *arguments, int count);
@@ -15,12 +15,7 @@ void serialize_event(char *buffer, Event *event) {
15
15
  return;
16
16
  }
17
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
18
  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
19
  char *method_name_str = RSTRING_PTR(method_name);
25
20
 
26
21
  sprintf(
@@ -30,8 +25,8 @@ void serialize_event(char *buffer, Event *event) {
30
25
  "method: %s, "
31
26
  "event: %d, "
32
27
  "for_singleton: %d",
33
- klass_name_str,
34
- self_name_str,
28
+ event->klass,
29
+ event->self_klass,
35
30
  method_name_str,
36
31
  event->event,
37
32
  event->for_singleton
@@ -6,18 +6,56 @@
6
6
  #include "current_trace.h"
7
7
  #include "utils.h"
8
8
  #include "configuration.h"
9
+ #include "st_name.h"
9
10
 
10
- VALUE extract_arguments(VALUE tp_val) {
11
+ struct MemoS {
12
+ int i;
13
+ Argument *arguments;
14
+ };
15
+
16
+ static void copy_str(char **target, VALUE string) {
17
+ *target = malloc(sizeof(char) * RSTRING_LEN(string) + 1);
18
+
19
+ memcpy(*target, RSTRING_PTR(string), RSTRING_LEN(string));
20
+ }
21
+
22
+ static int extract_kv(VALUE key, VALUE value, VALUE data) {
23
+ struct MemoS *memo = (struct MemoS *)data;
24
+
25
+ memo->arguments[memo->i].key = key;
26
+ copy_str(&memo->arguments[memo->i].value, value);
27
+
28
+ memo->i++;
29
+
30
+ return ST_CONTINUE;
31
+ }
32
+
33
+ static void extract_arguments(Event *event, VALUE tp_val) {
11
34
  VALUE main_module = rb_const_get(rb_cObject, rb_intern("StackTrace"));
12
35
  VALUE extractor_class = rb_const_get(main_module, rb_intern("ArgumentExtractor"));
13
36
 
14
- VALUE arguments = rb_funcall(extractor_class, rb_intern("extract"), 1, tp_val);
15
- rb_gc_register_address(&arguments);
37
+ VALUE arguments_hash = rb_funcall(extractor_class, rb_intern("extract"), 1, tp_val);
38
+ VALUE hash_size = rb_funcall(arguments_hash, rb_intern("size"), 0);
39
+
40
+ int arguments_count = FIX2INT(hash_size);
41
+
42
+ if(arguments_count == 0) return;
43
+
44
+ event->arguments_count = arguments_count;
45
+ event->arguments = malloc(sizeof(Argument) * arguments_count);
16
46
 
17
- return arguments;
47
+ struct MemoS memo = { 0, event->arguments };
48
+
49
+ rb_hash_foreach(arguments_hash, extract_kv, (VALUE)&memo);
18
50
  }
19
51
 
20
52
  void create_event(VALUE tp_val, void *_data) {
53
+ Trace *current_trace = get_current_trace();
54
+
55
+ // This can happen if a new thread spawns in trace scope.
56
+ // TODO: Save them with their thread identifier.
57
+ if(current_trace == NULL) return;
58
+
21
59
  Event event = {};
22
60
  int for_singleton = false;
23
61
 
@@ -29,37 +67,50 @@ void create_event(VALUE tp_val, void *_data) {
29
67
  VALUE self_klass;
30
68
 
31
69
  if(FL_TEST(klass, FL_SINGLETON)) {
32
- klass = rb_ivar_get(klass, rb_intern("__attached__"));
33
70
  for_singleton = true;
34
- self_klass = rb_funcall(self, rb_intern("name"), 0);
71
+ klass = rb_ivar_get(klass, rb_intern("__attached__"));
72
+ self_klass = self;
35
73
  } else {
36
- VALUE class = rb_funcall(self, rb_intern("class"), 0);
37
- self_klass = rb_funcall(class, rb_intern("name"), 0);
74
+ self_klass = CLASS_OF(self);
38
75
  }
39
76
 
40
- event.trace = get_current_trace();
41
- event.tp_val = tp_val;
42
- event.trace_arg = trace_arg;
77
+ VALUE receiver = st_name(self, klass);
78
+ VALUE klass_name = get_cname(klass);
79
+ VALUE self_klass_name = get_cname(self_klass);
80
+
81
+ if(receiver == Qundef || klass_name == Qundef || self_klass_name == Qundef) return;
82
+ if(!rb_obj_is_kind_of(klass_name, rb_cString) || !rb_obj_is_kind_of(self_klass_name, rb_cString)) return; // These values can be Qnil
83
+
84
+ copy_str(&event.receiver, receiver);
85
+ copy_str(&event.klass, klass_name);
86
+ copy_str(&event.self_klass, self_klass_name);
87
+
88
+ event.trace = current_trace;
43
89
  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
90
  event.method = method;
48
91
  event.for_singleton = for_singleton;
49
- event.return_value = Qundef;
50
- event.arguments = Qundef;
92
+ event.return_value = NULL;
93
+ event.arguments = NULL;
51
94
  event.at = get_monotonic_m_secs();
52
95
 
53
- if(event.event == RUBY_EVENT_RAISE)
54
- event.raised_exception = rb_tracearg_raised_exception(trace_arg);
96
+ if(event.event == RUBY_EVENT_RAISE) {
97
+ VALUE exception = rb_tracearg_raised_exception(trace_arg);
98
+ VALUE exception_to_s = rb_funcall(exception, rb_intern("to_s"), 0);
99
+
100
+ copy_str(&event.raised_exception, exception_to_s);
101
+ }
55
102
 
56
103
  if(RTEST(get_inspect_arguments()) &&
57
104
  (event.event == RUBY_EVENT_CALL || event.event == RUBY_EVENT_C_CALL || event.event == RUBY_EVENT_B_CALL))
58
- event.arguments = extract_arguments(tp_val);
105
+ extract_arguments(&event, tp_val);
59
106
 
60
107
  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);
108
+ (event.event == RUBY_EVENT_RETURN || event.event == RUBY_EVENT_C_RETURN || event.event == RUBY_EVENT_B_RETURN)) {
109
+ VALUE return_value = rb_tracearg_return_value(trace_arg);
110
+ VALUE return_value_st_name = rb_funcall(return_value, rb_intern("st_name"), 0);
111
+
112
+ copy_str(&event.return_value, return_value_st_name);
113
+ }
63
114
 
64
115
  produce_event(event);
65
116
  }
@@ -1,5 +1,6 @@
1
1
  #include "span.h"
2
2
  #include "utils.h"
3
+ #include "argument.h"
3
4
 
4
5
  #define CHILDREN_BUF_INC_SIZE 10
5
6
 
@@ -11,9 +12,10 @@ Span *create_span(Event *event) {
11
12
  span->klass = event->klass;
12
13
  span->self_klass = event->self_klass;
13
14
  span->method = event->method;
14
- span->return_value = Qundef;
15
+ span->return_value = NULL;
15
16
  span->arguments = event->arguments;
16
- span->exception = Qundef;
17
+ span->arguments_count = event->arguments_count;
18
+ span->exception = NULL;
17
19
  span->children_count = 0;
18
20
  span->singleton = event->for_singleton ? Qtrue : Qfalse;
19
21
 
@@ -48,7 +50,6 @@ Span *close_span(Span *span, Event *event) {
48
50
  return span->caller;
49
51
  }
50
52
 
51
-
52
53
  // Deallocate the memory occupied by span
53
54
  // and its children.
54
55
  void free_span(Span *span) {
@@ -61,6 +62,24 @@ void free_span(Span *span) {
61
62
  free(span->children);
62
63
  }
63
64
 
65
+ if(span->receiver != NULL)
66
+ free(span->receiver);
67
+
68
+ if(span->klass != NULL)
69
+ free(span->klass);
70
+
71
+ if(span->self_klass != NULL)
72
+ free(span->self_klass);
73
+
74
+ if(span->return_value != NULL)
75
+ free(span->return_value);
76
+
77
+ if(span->arguments != NULL)
78
+ free_arguments(span->arguments, span->arguments_count);
79
+
80
+ if(span->exception != NULL)
81
+ free(span->exception);
82
+
64
83
  free(span);
65
84
  }
66
85
 
@@ -68,27 +87,36 @@ int duration_of(Span *span) {
68
87
  return (int)(span->finished_at - span->started_at);
69
88
  }
70
89
 
90
+ VALUE serialize_arguments(Argument *arguments, int count) {
91
+ VALUE hash = rb_hash_new();
92
+ int i;
93
+
94
+ for(i = 0; i < count; i++) {
95
+ rb_hash_aset(hash, arguments[i].key, rb_str_new_cstr(arguments[i].value));
96
+ }
97
+
98
+ return hash;
99
+ }
100
+
71
101
  VALUE span_to_ruby_hash(Span *span) {
72
102
  VALUE hash = rb_hash_new();
73
103
 
74
- rb_hash_aset(hash, rb_str_new2("receiver"), span->receiver);
75
- rb_hash_aset(hash, rb_str_new2("defined_class"), span->klass);
76
- rb_hash_aset(hash, rb_str_new2("self_class"), span->self_klass);
104
+ rb_hash_aset(hash, rb_str_new2("receiver"), rb_str_new_cstr(span->receiver));
105
+ rb_hash_aset(hash, rb_str_new2("defined_class"), rb_str_new_cstr(span->klass));
106
+ rb_hash_aset(hash, rb_str_new2("self_class"), rb_str_new_cstr(span->self_klass));
77
107
  rb_hash_aset(hash, rb_str_new2("method_name"), span->method);
78
108
  rb_hash_aset(hash, rb_str_new2("singleton"), span->singleton);
79
109
  rb_hash_aset(hash, rb_str_new2("duration"), INT2FIX(duration_of(span)));
80
110
  rb_hash_aset(hash, rb_str_new2("spans"), to_ruby_array(span->children_count, span->children));
81
111
 
82
- if(span->exception != Qundef)
83
- rb_hash_aset(hash, rb_str_new2("exception"), span->exception);
84
-
85
- if(span->return_value != Qundef)
86
- rb_hash_aset(hash, rb_str_new2("return_value"), rb_funcall(span->return_value, rb_intern("st_name"), 0));
112
+ if(span->exception != NULL)
113
+ rb_hash_aset(hash, rb_str_new2("exception"), rb_str_new_cstr(span->exception));
87
114
 
88
- if(span->arguments != Qundef) {
89
- rb_gc_unregister_address(&span->arguments);
115
+ if(span->return_value != NULL)
116
+ rb_hash_aset(hash, rb_str_new2("return_value"), rb_str_new_cstr(span->return_value));
90
117
 
91
- rb_hash_aset(hash, rb_str_new2("arguments"), span->arguments);
118
+ if(span->arguments != NULL) {
119
+ rb_hash_aset(hash, rb_str_new2("arguments"), serialize_arguments(span->arguments, span->arguments_count));
92
120
  }
93
121
 
94
122
  return hash;
@@ -0,0 +1,47 @@
1
+ #include "st_name.h"
2
+
3
+ static VALUE extract_st_name(VALUE object) {
4
+ return rb_funcall(object, rb_intern("st_name"), 0);
5
+ }
6
+
7
+ VALUE get_cname(VALUE constant) {
8
+ if(rb_obj_is_kind_of(constant, rb_cClass)) {
9
+ return rb_class_name(constant);
10
+ } else if(rb_obj_is_kind_of(constant, rb_cModule)) {
11
+ return rb_mod_name(constant);
12
+ } else {
13
+ return Qundef; // This is still possible!
14
+ }
15
+ }
16
+
17
+ static VALUE object_name_for_cBasicObject(VALUE object, VALUE klass) {
18
+ VALUE cname = get_cname(klass);
19
+
20
+ if(cname == Qundef) return Qundef;
21
+
22
+ return rb_sprintf("#<%"PRIsVALUE":%p>", cname, (void*)object);
23
+ }
24
+
25
+ static VALUE object_name_for_cObject(VALUE object, VALUE klass) {
26
+ int status;
27
+
28
+ VALUE st_name = rb_protect(extract_st_name, object, &status);
29
+
30
+ if(status != 0) {
31
+ rb_set_errinfo(Qnil);
32
+
33
+ return object_name_for_cBasicObject(object, klass);
34
+ } else {
35
+ return st_name;
36
+ }
37
+ }
38
+
39
+ VALUE st_name(VALUE object, VALUE klass) {
40
+ if(rb_obj_is_kind_of(object, rb_cObject)) {
41
+ return object_name_for_cObject(object, klass);
42
+ } else if(rb_obj_is_kind_of(object, rb_cBasicObject)) {
43
+ return object_name_for_cBasicObject(object, klass);
44
+ } else {
45
+ return Qundef;
46
+ }
47
+ }
@@ -0,0 +1,4 @@
1
+ #include <ruby.h>
2
+
3
+ VALUE st_name(VALUE object, VALUE klass);
4
+ VALUE get_cname(VALUE constant);
@@ -8,18 +8,19 @@
8
8
  #include "span.h"
9
9
  #include "debug.h"
10
10
  #include "current_trace.h"
11
+ #include "argument.h"
11
12
 
12
13
  static VALUE check_proc;
13
14
 
14
15
  pthread_cond_t trace_finished = PTHREAD_COND_INITIALIZER;
15
16
  pthread_mutex_t trace_access_mutex = PTHREAD_MUTEX_INITIALIZER;
16
17
 
17
- void free_trace(Trace *trace) {
18
+ static void free_trace(Trace *trace) {
18
19
  free_span(trace->top_span);
19
20
  free(trace);
20
21
  }
21
22
 
22
- void process_obsolote_event(Event *event) {
23
+ static void process_obsolote_event(Event *event) {
23
24
  // Free this trace as there is no reference to it anymore!
24
25
  free_trace(event->trace);
25
26
  }
@@ -28,16 +29,51 @@ void set_check_proc(VALUE proc) {
28
29
  check_proc = proc;
29
30
  }
30
31
 
31
- bool is_tracked_event(Event *event) {
32
+ static VALUE call_proc(VALUE val) {
33
+ Event *event = (Event *)val;
34
+
35
+ return rb_funcall(check_proc, rb_intern("call"), 2, rb_str_new_cstr(event->self_klass), event->method);
36
+ }
37
+
38
+ static bool is_tracked_event(Event *event) {
32
39
  if(!RTEST(check_proc)) return true; // Check proc is not configured, all the events will be tracked.
33
40
 
34
- VALUE result = rb_funcall(check_proc, rb_intern("call"), 2, event->self_klass, event->method);
41
+ int state;
42
+ VALUE result = rb_protect(call_proc, (VALUE)event, &state); // I don't really like allocating a new array for each call so that's why I use this hack!
43
+
44
+ if(state != 0) {
45
+ rb_p(rb_errinfo());
46
+
47
+ rb_set_errinfo(Qnil);
48
+
49
+ return false;
50
+ }
35
51
 
36
52
  return RTEST(result);
37
53
  }
38
54
 
55
+ static void free_event_members(Event *event) {
56
+ if(event->receiver != NULL)
57
+ free(event->receiver);
58
+
59
+ if(event->klass != NULL)
60
+ free(event->klass);
61
+
62
+ if(event->self_klass != NULL)
63
+ free(event->self_klass);
64
+
65
+ if(event->return_value != NULL)
66
+ free(event->return_value);
67
+
68
+ if(event->raised_exception != NULL)
69
+ free(event->raised_exception);
70
+
71
+ if(event->arguments != NULL)
72
+ free_arguments(event->arguments, event->arguments_count);
73
+ }
74
+
39
75
  void create_new_span(Event *event) {
40
- if(!is_tracked_event(event)) return;
76
+ if(!is_tracked_event(event)) return free_event_members(event);
41
77
 
42
78
  Span *new_span = create_span(event);
43
79
 
@@ -47,7 +83,7 @@ void create_new_span(Event *event) {
47
83
  }
48
84
 
49
85
  void close_current_span(Event *event) {
50
- if(!is_tracked_event(event)) return;
86
+ if(!is_tracked_event(event)) return free_event_members(event);
51
87
 
52
88
  Trace *trace = event->trace;
53
89
 
@@ -0,0 +1,12 @@
1
+ #include <ruby.h>
2
+
3
+ #ifndef ARGUMENT_H
4
+ #define ARGUMENT_H
5
+
6
+ typedef struct ArgumentS Argument;
7
+
8
+ struct ArgumentS {
9
+ VALUE key;
10
+ char *value;
11
+ };
12
+ #endif
@@ -4,6 +4,8 @@
4
4
  #include <stdbool.h>
5
5
  #include <sys/time.h>
6
6
 
7
+ #include "types/argument.h"
8
+
7
9
  #ifndef EVENT_H
8
10
  #define EVENT_H
9
11
 
@@ -15,16 +17,15 @@
15
17
 
16
18
  struct EventS {
17
19
  Trace *trace;
18
- VALUE tp_val;
19
20
  rb_event_flag_t event;
20
- rb_trace_arg_t *trace_arg;
21
- VALUE klass;
22
- VALUE self_klass;
23
- VALUE receiver;
24
- VALUE method;
25
- VALUE raised_exception;
26
- VALUE return_value;
27
- VALUE arguments;
21
+ char *receiver;
22
+ char *klass;
23
+ char *self_klass;
24
+ VALUE method; // This is a symbol anyway
25
+ char *return_value;
26
+ Argument *arguments;
27
+ int arguments_count;
28
+ char *raised_exception;
28
29
  bool for_singleton;
29
30
  long int at;
30
31
  };
@@ -1,3 +1,5 @@
1
+ #include "types/argument.h"
2
+
1
3
  #ifndef SPAN_H
2
4
  #define SPAN_H
3
5
 
@@ -7,14 +9,15 @@
7
9
  long int started_at;
8
10
  long int finished_at;
9
11
 
10
- VALUE klass;
11
- VALUE self_klass;
12
- VALUE receiver;
12
+ char *receiver;
13
+ char *klass;
14
+ char *self_klass;
13
15
  VALUE method;
14
16
  VALUE singleton;
15
- VALUE exception;
16
- VALUE return_value;
17
- VALUE arguments;
17
+ char *return_value;
18
+ Argument *arguments;
19
+ int arguments_count;
20
+ char *exception;
18
21
  Span *caller;
19
22
  int children_count;
20
23
  Span **children;
@@ -7,14 +7,14 @@ module StackTrace
7
7
  trace_point.parameters
8
8
  .map(&:last)
9
9
  .each_with_object({}) do |parameter, memo|
10
- memo[parameter] = extract_argument(trace_point, parameter)
10
+ memo[parameter] = extract_argument(trace_point, parameter).st_name
11
11
  end
12
12
  end
13
13
 
14
14
  private
15
15
 
16
16
  def extract_argument(trace_point, parameter)
17
- trace_point.binding.eval(parameter.to_s).st_name
17
+ trace_point.binding.eval(parameter.to_s)
18
18
  rescue Exception # SyntaxError can happen as we are calling `eval` here!
19
19
  end
20
20
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  class FalseClass
4
4
  def st_name
5
- self
5
+ inspect
6
6
  end
7
7
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  class NilClass
4
4
  def st_name
5
- self
5
+ inspect
6
6
  end
7
7
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  class Numeric
4
4
  def st_name
5
- self
5
+ inspect
6
6
  end
7
7
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  class TrueClass
4
4
  def st_name
5
- self
5
+ inspect
6
6
  end
7
7
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StackTrace
4
- VERSION = "0.4.0"
4
+ VERSION = "0.6.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stack_trace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mehmet Emin INAC
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-04-06 00:00:00.000000000 Z
11
+ date: 2023-04-09 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: StackTrace
14
14
  email:
@@ -26,6 +26,8 @@ files:
26
26
  - LICENSE.txt
27
27
  - README.md
28
28
  - Rakefile
29
+ - ext/stack_trace/argument.c
30
+ - ext/stack_trace/argument.h
29
31
  - ext/stack_trace/configuration.c
30
32
  - ext/stack_trace/configuration.h
31
33
  - ext/stack_trace/current_trace.c
@@ -41,9 +43,12 @@ files:
41
43
  - ext/stack_trace/sidecar.h
42
44
  - ext/stack_trace/span.c
43
45
  - ext/stack_trace/span.h
46
+ - ext/stack_trace/st_name.c
47
+ - ext/stack_trace/st_name.h
44
48
  - ext/stack_trace/stack_trace.c
45
49
  - ext/stack_trace/trace.c
46
50
  - ext/stack_trace/trace.h
51
+ - ext/stack_trace/types/argument.h
47
52
  - ext/stack_trace/types/event.h
48
53
  - ext/stack_trace/types/span.h
49
54
  - ext/stack_trace/types/trace.h