blab 0.0.0 → 0.0.1.pre.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +156 -1
- data/ext/Makefile +266 -0
- data/ext/blab_trace.bundle +0 -0
- data/ext/blab_trace.c +186 -0
- data/ext/blab_trace.o +0 -0
- data/ext/extconf.h +9 -0
- data/ext/extconf.rb +15 -0
- data/ext/mkmf.log +86 -0
- data/lib/blab.rb +25 -3
- data/lib/blab/config.rb +57 -0
- data/lib/blab/formatter.rb +48 -0
- data/lib/blab/printer.rb +83 -0
- data/lib/blab/tracer.rb +86 -0
- data/lib/blab/version.rb +1 -1
- data/test/support/test.rb +63 -0
- metadata +36 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e0f2fa8c029f19b494bc57a4fddf76cb8c5b5265e208c7630e1d56cdaf52cb1d
|
4
|
+
data.tar.gz: 16b98eb6a98c16491e650169e4b0bfeea0c6b43b31cfdff9741a2a97443c0c33
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b0ce5055f845ad8eeb3cc1daf1c93532cb927e471830413baba7b2b75565d0b91cd6bcdf0d340c352a3e8c2a6fe95bac3e531d74c6ac61a80c462953e1590c5
|
7
|
+
data.tar.gz: da14317d5e95869fbadd1c57d809a8878341dcd6dd6c9c65216c2f8c0d3757cba593b8681ef284f333f85d46aa7bb72c57be440284271f8996f515bd0aa4a334
|
data/README.md
CHANGED
@@ -1,2 +1,157 @@
|
|
1
1
|
# blab
|
2
|
-
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/blab.svg)](https://badge.fury.io/rb/blab)
|
3
|
+
|
4
|
+
A debugging tool.
|
5
|
+
|
6
|
+
The gem allows to trace local variables and memory usage for a specific Ruby code. It's rather experemental and is intended for use in a development environment only. \
|
7
|
+
Blab is inspired by [PySnooper](https://github.com/cool-RR/PySnooper).
|
8
|
+
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Put this line in your Gemfile
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
gem "blab", group: :development
|
16
|
+
```
|
17
|
+
|
18
|
+
Then run
|
19
|
+
|
20
|
+
```
|
21
|
+
bundle install
|
22
|
+
```
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
Include `Blab` module and the destionation class and use the `blab` decorator in front of a method defenition.
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
require "blab"
|
30
|
+
|
31
|
+
class Test
|
32
|
+
include Blab
|
33
|
+
|
34
|
+
blab def longest_rep(str)
|
35
|
+
max = str.chars.chunk(&:itself).map(&:last).max_by(&:size)
|
36
|
+
max ? [max[0], max.size] : ["", 0]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
Test.new.longest_rep("cbaaabb")
|
41
|
+
|
42
|
+
```
|
43
|
+
|
44
|
+
The output to STDOUT:
|
45
|
+
|
46
|
+
```
|
47
|
+
Var......... str="cbaaabb"
|
48
|
+
18:17:26.042 call test/support/test.rb:46 13463552 blab def longest_rep(str)
|
49
|
+
18:17:26.042 line test/support/test.rb:47 13508608 max = str.chars.chunk(&:itself).map(&:last).max_by(&:size)
|
50
|
+
Var......... max=["a", "a", "a"]
|
51
|
+
18:17:26.043 line test/support/test.rb:48 13516800 max ? [max[0], max.size] : ["", 0]
|
52
|
+
18:17:26.043 return test/support/test.rb:49 13516800 end
|
53
|
+
```
|
54
|
+
|
55
|
+
The output is configurable. Within the example the 4th item in a table is `ru_maxss` - a memory amount used by the Ruby process. The value is in bytes on Mac OS X (Darwin), but in kilobytes on BSD and Linux. In the example it's in bytes and is roughly 13MB total.
|
56
|
+
Note, that blab itself adds some overhead, and the program'll take lesser memory running without it.
|
57
|
+
|
58
|
+
The gem allows to wrap only a piece of code in a block:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
class Test
|
62
|
+
include Blab
|
63
|
+
|
64
|
+
def shuffle(arr)
|
65
|
+
for n in 0...arr.size
|
66
|
+
targ = n + rand(arr.size - n)
|
67
|
+
arr[n], arr[targ] = arr[targ], arr[n] if n != targ
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def pairs(a, b)
|
72
|
+
with_blab do
|
73
|
+
a << "Insane"
|
74
|
+
shuffle(b)
|
75
|
+
end
|
76
|
+
b.each { |x| shuffle(a); a.each { |y| print y, " ", x, ".\n" } }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
Test.new.pairs(["Bored", "Curious"], ["cat", "frog"])
|
81
|
+
```
|
82
|
+
|
83
|
+
The output:
|
84
|
+
|
85
|
+
```
|
86
|
+
Var......... a=["Bored", "Curious"]
|
87
|
+
Var......... b=["cat", "frog"]
|
88
|
+
18:38:15.188 line test/support/test.rb:54 13770752 a << "Insane"
|
89
|
+
18:38:15.188 line test/support/test.rb:55 13807616 shuffle(b)
|
90
|
+
Var......... arr=["cat", "frog"]
|
91
|
+
18:38:15.188 call test/support/test.rb:45 13807616 def shuffle(arr)
|
92
|
+
18:38:15.189 line test/support/test.rb:46 13807616 for n in 0...arr.size
|
93
|
+
Var......... n=0
|
94
|
+
18:38:15.189 line test/support/test.rb:47 13811712 targ = n + rand(arr.size - n)
|
95
|
+
Var......... targ=0
|
96
|
+
18:38:15.189 line test/support/test.rb:48 13811712 arr[n], arr[targ] = arr[targ], arr[n] if n != targ
|
97
|
+
Var......... n=1
|
98
|
+
18:38:15.189 line test/support/test.rb:47 13811712 targ = n + rand(arr.size - n)
|
99
|
+
Var......... targ=1
|
100
|
+
18:38:15.189 line test/support/test.rb:48 13811712 arr[n], arr[targ] = arr[targ], arr[n] if n != targ
|
101
|
+
18:38:15.189 return test/support/test.rb:50 13811712 end
|
102
|
+
```
|
103
|
+
|
104
|
+
## Configuration
|
105
|
+
|
106
|
+
Output to a file:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
Blab::Config.log_output = "log/blab.log"
|
110
|
+
```
|
111
|
+
|
112
|
+
Datetime format:
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
Blab::Config.datetime_format = "%H:%M:%S.%L"
|
116
|
+
```
|
117
|
+
|
118
|
+
Custom logger:
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
Blab::Config.logger = MyCustomLogger.new
|
122
|
+
```
|
123
|
+
|
124
|
+
Trace C calls your program makes from Ruby:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
Blab::Config.trace_c_calls = true
|
128
|
+
```
|
129
|
+
|
130
|
+
Trace only within the original scope. \
|
131
|
+
It means that the trace will be showed only for the current method and it will skip all external call's traces.
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
Blab::Config.original_scope_only = true
|
135
|
+
```
|
136
|
+
|
137
|
+
Format output. Available config is:
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
output_order = [
|
141
|
+
{ type: :time, order: 1, width: 12 },
|
142
|
+
{ type: :event, order: 2, width: 6 },
|
143
|
+
{ type: :file_lines, order: 3, width: 30 },
|
144
|
+
{ type: :class_name, order: 4, width: 10 },
|
145
|
+
{ type: :method_name, order: 5, width: 12 },
|
146
|
+
{ type: :ru_maxss, order: 6, width: 12 },
|
147
|
+
{ type: :code_lines, order: 7, width: 120 }
|
148
|
+
]
|
149
|
+
|
150
|
+
Blab::Config.output_order = output_order
|
151
|
+
```
|
152
|
+
By default it doesn't show current class name and method name. You can adjust the width, change the order, skip/add the desired output info.
|
153
|
+
|
154
|
+
## License
|
155
|
+
|
156
|
+
MIT
|
157
|
+
|
data/ext/Makefile
ADDED
@@ -0,0 +1,266 @@
|
|
1
|
+
|
2
|
+
SHELL = /bin/sh
|
3
|
+
|
4
|
+
# V=0 quiet, V=1 verbose. other values don't work.
|
5
|
+
V = 0
|
6
|
+
Q1 = $(V:1=)
|
7
|
+
Q = $(Q1:0=@)
|
8
|
+
ECHO1 = $(V:1=@ :)
|
9
|
+
ECHO = $(ECHO1:0=@ echo)
|
10
|
+
NULLCMD = :
|
11
|
+
|
12
|
+
#### Start of system configuration section. ####
|
13
|
+
|
14
|
+
srcdir = .
|
15
|
+
topdir = /Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0
|
16
|
+
hdrdir = $(topdir)
|
17
|
+
arch_hdrdir = /Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/x86_64-darwin16
|
18
|
+
PATH_SEPARATOR = :
|
19
|
+
VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
|
20
|
+
prefix = $(DESTDIR)/Users/july/.rbenv/versions/2.6.0
|
21
|
+
rubysitearchprefix = $(rubylibprefix)/$(sitearch)
|
22
|
+
rubyarchprefix = $(rubylibprefix)/$(arch)
|
23
|
+
rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
|
24
|
+
exec_prefix = $(prefix)
|
25
|
+
vendorarchhdrdir = $(vendorhdrdir)/$(sitearch)
|
26
|
+
sitearchhdrdir = $(sitehdrdir)/$(sitearch)
|
27
|
+
rubyarchhdrdir = $(rubyhdrdir)/$(arch)
|
28
|
+
vendorhdrdir = $(rubyhdrdir)/vendor_ruby
|
29
|
+
sitehdrdir = $(rubyhdrdir)/site_ruby
|
30
|
+
rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME)
|
31
|
+
vendorarchdir = $(vendorlibdir)/$(sitearch)
|
32
|
+
vendorlibdir = $(vendordir)/$(ruby_version)
|
33
|
+
vendordir = $(rubylibprefix)/vendor_ruby
|
34
|
+
sitearchdir = $(sitelibdir)/$(sitearch)
|
35
|
+
sitelibdir = $(sitedir)/$(ruby_version)
|
36
|
+
sitedir = $(rubylibprefix)/site_ruby
|
37
|
+
rubyarchdir = $(rubylibdir)/$(arch)
|
38
|
+
rubylibdir = $(rubylibprefix)/$(ruby_version)
|
39
|
+
sitearchincludedir = $(includedir)/$(sitearch)
|
40
|
+
archincludedir = $(includedir)/$(arch)
|
41
|
+
sitearchlibdir = $(libdir)/$(sitearch)
|
42
|
+
archlibdir = $(libdir)/$(arch)
|
43
|
+
ridir = $(datarootdir)/$(RI_BASE_NAME)
|
44
|
+
mandir = $(datarootdir)/man
|
45
|
+
localedir = $(datarootdir)/locale
|
46
|
+
libdir = $(exec_prefix)/lib
|
47
|
+
psdir = $(docdir)
|
48
|
+
pdfdir = $(docdir)
|
49
|
+
dvidir = $(docdir)
|
50
|
+
htmldir = $(docdir)
|
51
|
+
infodir = $(datarootdir)/info
|
52
|
+
docdir = $(datarootdir)/doc/$(PACKAGE)
|
53
|
+
oldincludedir = $(SDKROOT)/usr/include
|
54
|
+
includedir = $(prefix)/include
|
55
|
+
localstatedir = $(prefix)/var
|
56
|
+
sharedstatedir = $(prefix)/com
|
57
|
+
sysconfdir = $(prefix)/etc
|
58
|
+
datadir = $(datarootdir)
|
59
|
+
datarootdir = $(prefix)/share
|
60
|
+
libexecdir = $(exec_prefix)/libexec
|
61
|
+
sbindir = $(exec_prefix)/sbin
|
62
|
+
bindir = $(exec_prefix)/bin
|
63
|
+
archdir = $(rubyarchdir)
|
64
|
+
|
65
|
+
|
66
|
+
CC_WRAPPER =
|
67
|
+
CC = clang
|
68
|
+
CXX = clang++
|
69
|
+
LIBRUBY = $(LIBRUBY_A)
|
70
|
+
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
|
71
|
+
LIBRUBYARG_SHARED =
|
72
|
+
LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static -framework Security -framework Foundation $(MAINLIBS)
|
73
|
+
empty =
|
74
|
+
OUTFLAG = -o $(empty)
|
75
|
+
COUTFLAG = -o $(empty)
|
76
|
+
CSRCFLAG = $(empty)
|
77
|
+
|
78
|
+
RUBY_EXTCONF_H =
|
79
|
+
cflags = $(optflags) $(debugflags) $(warnflags)
|
80
|
+
cxxflags = $(optflags) $(debugflags) $(warnflags)
|
81
|
+
optflags = -O3
|
82
|
+
debugflags = -ggdb3
|
83
|
+
warnflags = -Wall -Wextra -Wdeclaration-after-statement -Wdeprecated-declarations -Wdivision-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wmissing-noreturn -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wextra-tokens
|
84
|
+
cppflags =
|
85
|
+
CCDLFLAGS = -fno-common
|
86
|
+
CFLAGS = $(CCDLFLAGS) $(cflags) -pipe $(ARCH_FLAG)
|
87
|
+
INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
|
88
|
+
DEFS =
|
89
|
+
CPPFLAGS = -DHAVE_VM_CORE_H -DHAVE_ISEQ_H -I/Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0
|
90
|
+
CXXFLAGS = $(CCDLFLAGS) $(cxxflags) $(ARCH_FLAG)
|
91
|
+
ldflags = -L. -L/Users/july/.rbenv/versions/2.6.0/lib -fstack-protector-strong -L/usr/local/lib
|
92
|
+
dldflags = -L/Users/july/.rbenv/versions/2.6.0/lib -Wl,-undefined,dynamic_lookup -Wl,-multiply_defined,suppress
|
93
|
+
ARCH_FLAG =
|
94
|
+
DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG)
|
95
|
+
LDSHARED = $(CC) -dynamic -bundle
|
96
|
+
LDSHAREDXX = $(CXX) -dynamic -bundle
|
97
|
+
AR = libtool -static
|
98
|
+
EXEEXT =
|
99
|
+
|
100
|
+
RUBY_INSTALL_NAME = $(RUBY_BASE_NAME)
|
101
|
+
RUBY_SO_NAME = ruby.2.6
|
102
|
+
RUBYW_INSTALL_NAME =
|
103
|
+
RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version)
|
104
|
+
RUBYW_BASE_NAME = rubyw
|
105
|
+
RUBY_BASE_NAME = ruby
|
106
|
+
|
107
|
+
arch = x86_64-darwin16
|
108
|
+
sitearch = $(arch)
|
109
|
+
ruby_version = 2.6.0
|
110
|
+
ruby = $(bindir)/$(RUBY_BASE_NAME)
|
111
|
+
RUBY = $(ruby)
|
112
|
+
ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h
|
113
|
+
|
114
|
+
RM = rm -f
|
115
|
+
RM_RF = $(RUBY) -run -e rm -- -rf
|
116
|
+
RMDIRS = rmdir -p
|
117
|
+
MAKEDIRS = mkdir -p
|
118
|
+
INSTALL = /usr/bin/install -c
|
119
|
+
INSTALL_PROG = $(INSTALL) -m 0755
|
120
|
+
INSTALL_DATA = $(INSTALL) -m 644
|
121
|
+
COPY = cp
|
122
|
+
TOUCH = exit >
|
123
|
+
|
124
|
+
#### End of system configuration section. ####
|
125
|
+
|
126
|
+
preload =
|
127
|
+
libpath = . $(libdir)
|
128
|
+
LIBPATH = -L. -L$(libdir)
|
129
|
+
DEFFILE =
|
130
|
+
|
131
|
+
CLEANFILES = mkmf.log
|
132
|
+
DISTCLEANFILES =
|
133
|
+
DISTCLEANDIRS =
|
134
|
+
|
135
|
+
extout =
|
136
|
+
extout_prefix =
|
137
|
+
target_prefix =
|
138
|
+
LOCAL_LIBS =
|
139
|
+
LIBS =
|
140
|
+
ORIG_SRCS = blab_trace.c
|
141
|
+
SRCS = $(ORIG_SRCS)
|
142
|
+
OBJS = blab_trace.o
|
143
|
+
HDRS = $(srcdir)/extconf.h
|
144
|
+
LOCAL_HDRS =
|
145
|
+
TARGET = blab_trace
|
146
|
+
TARGET_NAME = blab_trace
|
147
|
+
TARGET_ENTRY = Init_$(TARGET_NAME)
|
148
|
+
DLLIB = $(TARGET).bundle
|
149
|
+
EXTSTATIC =
|
150
|
+
STATIC_LIB =
|
151
|
+
|
152
|
+
TIMESTAMP_DIR = .
|
153
|
+
BINDIR = $(bindir)
|
154
|
+
RUBYCOMMONDIR = $(sitedir)$(target_prefix)
|
155
|
+
RUBYLIBDIR = $(sitelibdir)$(target_prefix)
|
156
|
+
RUBYARCHDIR = $(sitearchdir)$(target_prefix)
|
157
|
+
HDRDIR = $(rubyhdrdir)/ruby$(target_prefix)
|
158
|
+
ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix)
|
159
|
+
TARGET_SO_DIR =
|
160
|
+
TARGET_SO = $(TARGET_SO_DIR)$(DLLIB)
|
161
|
+
CLEANLIBS = $(TARGET_SO)
|
162
|
+
CLEANOBJS = *.o *.bak
|
163
|
+
|
164
|
+
all: $(DLLIB)
|
165
|
+
static: $(STATIC_LIB)
|
166
|
+
.PHONY: all install static install-so install-rb
|
167
|
+
.PHONY: clean clean-so clean-static clean-rb
|
168
|
+
|
169
|
+
clean-static::
|
170
|
+
clean-rb-default::
|
171
|
+
clean-rb::
|
172
|
+
clean-so::
|
173
|
+
clean: clean-so clean-static clean-rb-default clean-rb
|
174
|
+
-$(Q)$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time
|
175
|
+
|
176
|
+
distclean-rb-default::
|
177
|
+
distclean-rb::
|
178
|
+
distclean-so::
|
179
|
+
distclean-static::
|
180
|
+
distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb
|
181
|
+
-$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
|
182
|
+
-$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
|
183
|
+
-$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true
|
184
|
+
|
185
|
+
realclean: distclean
|
186
|
+
install: install-so install-rb
|
187
|
+
|
188
|
+
install-so: $(DLLIB) $(TIMESTAMP_DIR)/.sitearchdir.time
|
189
|
+
$(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
|
190
|
+
clean-static::
|
191
|
+
-$(Q)$(RM) $(STATIC_LIB)
|
192
|
+
install-rb: pre-install-rb do-install-rb install-rb-default
|
193
|
+
install-rb-default: pre-install-rb-default do-install-rb-default
|
194
|
+
pre-install-rb: Makefile
|
195
|
+
pre-install-rb-default: Makefile
|
196
|
+
do-install-rb:
|
197
|
+
do-install-rb-default:
|
198
|
+
pre-install-rb-default:
|
199
|
+
@$(NULLCMD)
|
200
|
+
$(TIMESTAMP_DIR)/.sitearchdir.time:
|
201
|
+
$(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR)
|
202
|
+
$(Q) $(TOUCH) $@
|
203
|
+
|
204
|
+
site-install: site-install-so site-install-rb
|
205
|
+
site-install-so: install-so
|
206
|
+
site-install-rb: install-rb
|
207
|
+
|
208
|
+
.SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S
|
209
|
+
|
210
|
+
.cc.o:
|
211
|
+
$(ECHO) compiling $(<)
|
212
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
|
213
|
+
|
214
|
+
.cc.S:
|
215
|
+
$(ECHO) translating $(<)
|
216
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
|
217
|
+
|
218
|
+
.mm.o:
|
219
|
+
$(ECHO) compiling $(<)
|
220
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
|
221
|
+
|
222
|
+
.mm.S:
|
223
|
+
$(ECHO) translating $(<)
|
224
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
|
225
|
+
|
226
|
+
.cxx.o:
|
227
|
+
$(ECHO) compiling $(<)
|
228
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
|
229
|
+
|
230
|
+
.cxx.S:
|
231
|
+
$(ECHO) translating $(<)
|
232
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
|
233
|
+
|
234
|
+
.cpp.o:
|
235
|
+
$(ECHO) compiling $(<)
|
236
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
|
237
|
+
|
238
|
+
.cpp.S:
|
239
|
+
$(ECHO) translating $(<)
|
240
|
+
$(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
|
241
|
+
|
242
|
+
.c.o:
|
243
|
+
$(ECHO) compiling $(<)
|
244
|
+
$(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
|
245
|
+
|
246
|
+
.c.S:
|
247
|
+
$(ECHO) translating $(<)
|
248
|
+
$(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
|
249
|
+
|
250
|
+
.m.o:
|
251
|
+
$(ECHO) compiling $(<)
|
252
|
+
$(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
|
253
|
+
|
254
|
+
.m.S:
|
255
|
+
$(ECHO) translating $(<)
|
256
|
+
$(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
|
257
|
+
|
258
|
+
$(TARGET_SO): $(OBJS) Makefile
|
259
|
+
$(ECHO) linking shared-object $(DLLIB)
|
260
|
+
-$(Q)$(RM) $(@)
|
261
|
+
$(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
|
262
|
+
$(Q) $(POSTLINK)
|
263
|
+
|
264
|
+
|
265
|
+
|
266
|
+
$(OBJS): $(HDRS) $(ruby_headers)
|
Binary file
|
data/ext/blab_trace.c
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
#include "extconf.h"
|
2
|
+
|
3
|
+
#define TRUE 1
|
4
|
+
#define FALSE 0
|
5
|
+
|
6
|
+
PUREFUNC(static rb_callable_method_entry_t *check_method_entry(VALUE obj, int can_be_svar));
|
7
|
+
static rb_callable_method_entry_t *check_method_entry(VALUE obj, int can_be_svar)
|
8
|
+
{
|
9
|
+
if (obj == Qfalse) return NULL;
|
10
|
+
|
11
|
+
#if VM_CHECK_MODE > 0
|
12
|
+
if (!RB_TYPE_P(obj, T_IMEMO)) rb_bug("check_method_entry: unknown type: %s", rb_obj_info(obj));
|
13
|
+
#endif
|
14
|
+
|
15
|
+
switch (imemo_type(obj)) {
|
16
|
+
case imemo_ment:
|
17
|
+
return (rb_callable_method_entry_t *)obj;
|
18
|
+
case imemo_cref:
|
19
|
+
return NULL;
|
20
|
+
case imemo_svar:
|
21
|
+
if (can_be_svar) {
|
22
|
+
return check_method_entry(((struct vm_svar *)obj)->cref_or_me, FALSE);
|
23
|
+
}
|
24
|
+
default:
|
25
|
+
#if VM_CHECK_MODE > 0
|
26
|
+
rb_bug("check_method_entry: svar should not be there:");
|
27
|
+
#endif
|
28
|
+
return NULL;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
MJIT_STATIC const rb_callable_method_entry_t *rb_vm_frame_method_entry(const rb_control_frame_t *cfp)
|
33
|
+
{
|
34
|
+
const VALUE *ep = cfp->ep;
|
35
|
+
rb_callable_method_entry_t *me;
|
36
|
+
|
37
|
+
while (!VM_ENV_LOCAL_P(ep)) {
|
38
|
+
if ((me = check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL) return me;
|
39
|
+
ep = VM_ENV_PREV_EP(ep);
|
40
|
+
}
|
41
|
+
|
42
|
+
return check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
|
43
|
+
}
|
44
|
+
|
45
|
+
|
46
|
+
int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, ID *called_idp, VALUE *klassp)
|
47
|
+
{
|
48
|
+
const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
|
49
|
+
|
50
|
+
if (me) {
|
51
|
+
if (idp) *idp = me->def->original_id;
|
52
|
+
if (called_idp) *called_idp = me->called_id;
|
53
|
+
if (klassp) *klassp = me->owner;
|
54
|
+
return TRUE;
|
55
|
+
}
|
56
|
+
else {
|
57
|
+
return FALSE;
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
int rb_ec_frame_method_id_and_class(const rb_execution_context_t *ec, ID *idp, ID *called_idp, VALUE *klassp)
|
62
|
+
{
|
63
|
+
return rb_vm_control_frame_id_and_class(ec->cfp, idp, called_idp, klassp);
|
64
|
+
}
|
65
|
+
|
66
|
+
inline static int calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
|
67
|
+
{
|
68
|
+
size_t pos = (size_t)(pc - iseq->body->iseq_encoded);
|
69
|
+
if (LIKELY(pos)) {
|
70
|
+
/* use pos-1 because PC points next instruction at the beginning of instruction */
|
71
|
+
pos--;
|
72
|
+
}
|
73
|
+
return rb_iseq_line_no(iseq, pos);
|
74
|
+
}
|
75
|
+
|
76
|
+
int rb_vm_get_sourceline(const rb_control_frame_t *cfp)
|
77
|
+
{
|
78
|
+
if (VM_FRAME_RUBYFRAME_P(cfp) && cfp->iseq) {
|
79
|
+
const rb_iseq_t *iseq = cfp->iseq;
|
80
|
+
int line = calc_lineno(iseq, cfp->pc);
|
81
|
+
if (line != 0) {
|
82
|
+
return line;
|
83
|
+
}
|
84
|
+
else {
|
85
|
+
return FIX2INT(rb_iseq_first_lineno(iseq));
|
86
|
+
}
|
87
|
+
}
|
88
|
+
else {
|
89
|
+
return 0;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
static const char * get_event_name(rb_event_flag_t event)
|
94
|
+
{
|
95
|
+
switch (event) {
|
96
|
+
case RUBY_EVENT_LINE: return "line";
|
97
|
+
case RUBY_EVENT_CLASS: return "class";
|
98
|
+
case RUBY_EVENT_END: return "end";
|
99
|
+
case RUBY_EVENT_CALL: return "call";
|
100
|
+
case RUBY_EVENT_RETURN: return "return";
|
101
|
+
case RUBY_EVENT_C_CALL: return "c-call";
|
102
|
+
case RUBY_EVENT_C_RETURN: return "c-return";
|
103
|
+
case RUBY_EVENT_RAISE: return "raise";
|
104
|
+
default: return "unknown";
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
static void get_path_and_lineno(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, rb_event_flag_t event, VALUE *pathp, int *linep)
|
109
|
+
{
|
110
|
+
cfp = rb_vm_get_ruby_level_next_cfp(ec, cfp);
|
111
|
+
|
112
|
+
if (cfp) {
|
113
|
+
const rb_iseq_t *iseq = cfp->iseq;
|
114
|
+
*pathp = rb_iseq_path(iseq);
|
115
|
+
|
116
|
+
if (event & (RUBY_EVENT_CLASS | RUBY_EVENT_CALL | RUBY_EVENT_B_CALL)) {
|
117
|
+
*linep = FIX2INT(rb_iseq_first_lineno(iseq));
|
118
|
+
}
|
119
|
+
else {
|
120
|
+
*linep = rb_vm_get_sourceline(cfp);
|
121
|
+
}
|
122
|
+
}
|
123
|
+
else {
|
124
|
+
*pathp = Qnil;
|
125
|
+
*linep = 0;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
static void blab_trace_func(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
|
130
|
+
{
|
131
|
+
int line;
|
132
|
+
VALUE filename;
|
133
|
+
VALUE eventname = rb_str_new2(get_event_name(event));
|
134
|
+
VALUE argv[7];
|
135
|
+
const rb_execution_context_t *ec = GET_EC();
|
136
|
+
|
137
|
+
// RUSAGE_SELF/RUSAGE_CHILDREN/RUSAGE_THREAD
|
138
|
+
struct rusage r_usage;
|
139
|
+
getrusage(RUSAGE_SELF, &r_usage);
|
140
|
+
|
141
|
+
get_path_and_lineno(ec, ec->cfp, event, &filename, &line);
|
142
|
+
|
143
|
+
if (!klass) {
|
144
|
+
rb_ec_frame_method_id_and_class(ec, &id, 0, &klass);
|
145
|
+
}
|
146
|
+
|
147
|
+
if (klass) {
|
148
|
+
if (RB_TYPE_P(klass, T_ICLASS)) {
|
149
|
+
klass = RBASIC(klass)->klass;
|
150
|
+
}
|
151
|
+
else if (FL_TEST(klass, FL_SINGLETON)) {
|
152
|
+
klass = rb_ivar_get(klass, id__attached__);
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
argv[0] = eventname;
|
157
|
+
argv[1] = filename;
|
158
|
+
argv[2] = INT2FIX(line);
|
159
|
+
argv[3] = id ? ID2SYM(id) : Qnil;
|
160
|
+
argv[4] = (self && (filename != Qnil)) ? rb_binding_new() : Qnil;
|
161
|
+
argv[5] = klass ? klass : Qnil;
|
162
|
+
argv[6] = INT2FIX(r_usage.ru_maxrss); // maximum resident set size
|
163
|
+
|
164
|
+
rb_proc_call_with_block(proc, 7, argv, Qnil);
|
165
|
+
}
|
166
|
+
|
167
|
+
static VALUE rb_blab_trace(VALUE obj, VALUE trace)
|
168
|
+
{
|
169
|
+
rb_remove_event_hook(blab_trace_func);
|
170
|
+
|
171
|
+
if (NIL_P(trace)) {
|
172
|
+
return Qnil;
|
173
|
+
}
|
174
|
+
|
175
|
+
if (!rb_obj_is_proc(trace)) {
|
176
|
+
rb_raise(rb_eTypeError, "trace_func needs to be Proc");
|
177
|
+
}
|
178
|
+
|
179
|
+
rb_add_event_hook(blab_trace_func, RUBY_EVENT_ALL, trace);
|
180
|
+
return trace;
|
181
|
+
}
|
182
|
+
|
183
|
+
void Init_blab_trace()
|
184
|
+
{
|
185
|
+
rb_define_global_function("blab_trace", rb_blab_trace, 1);
|
186
|
+
}
|
data/ext/blab_trace.o
ADDED
Binary file
|
data/ext/extconf.h
ADDED
data/ext/extconf.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "mkmf"
|
4
|
+
require "debase/ruby_core_source"
|
5
|
+
|
6
|
+
if RUBY_VERSION < "2.6"
|
7
|
+
STDERR.print("Ruby version must be 2.6 or older\n")
|
8
|
+
exit(1)
|
9
|
+
end
|
10
|
+
|
11
|
+
hdrs = proc { have_header("vm_core.h") and have_header("iseq.h") }
|
12
|
+
|
13
|
+
if !Debase::RubyCoreSource::create_makefile_with_core(hdrs, "blab_trace")
|
14
|
+
exit(1)
|
15
|
+
end
|
data/ext/mkmf.log
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
have_header: checking for vm_core.h... -------------------- no
|
2
|
+
|
3
|
+
"clang -o conftest -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/x86_64-darwin16 -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/ruby/backward -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0 -I. -I/Users/july/.rbenv/versions/2.6.0/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT -O3 -ggdb3 -Wall -Wextra -Wdeclaration-after-statement -Wdeprecated-declarations -Wdivision-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wmissing-noreturn -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wextra-tokens -pipe conftest.c -L. -L/Users/july/.rbenv/versions/2.6.0/lib -L. -L/Users/july/.rbenv/versions/2.6.0/lib -fstack-protector-strong -L/usr/local/lib -lruby.2.6-static -framework Security -framework Foundation -lpthread -lgmp -ldl -lobjc "
|
4
|
+
checked program was:
|
5
|
+
/* begin */
|
6
|
+
1: #include "ruby.h"
|
7
|
+
2:
|
8
|
+
3: int main(int argc, char **argv)
|
9
|
+
4: {
|
10
|
+
5: return 0;
|
11
|
+
6: }
|
12
|
+
/* end */
|
13
|
+
|
14
|
+
"clang -E -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/x86_64-darwin16 -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/ruby/backward -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0 -I. -I/Users/july/.rbenv/versions/2.6.0/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT -O3 -ggdb3 -Wall -Wextra -Wdeclaration-after-statement -Wdeprecated-declarations -Wdivision-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wmissing-noreturn -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wextra-tokens -pipe conftest.c -o conftest.i"
|
15
|
+
conftest.c:3:10: fatal error: 'vm_core.h' file not found
|
16
|
+
#include <vm_core.h>
|
17
|
+
^~~~~~~~~~~
|
18
|
+
1 error generated.
|
19
|
+
checked program was:
|
20
|
+
/* begin */
|
21
|
+
1: #include "ruby.h"
|
22
|
+
2:
|
23
|
+
3: #include <vm_core.h>
|
24
|
+
/* end */
|
25
|
+
|
26
|
+
--------------------
|
27
|
+
|
28
|
+
have_header: checking for vm_core.h... -------------------- no
|
29
|
+
|
30
|
+
"clang -E -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/x86_64-darwin16 -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/ruby/backward -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0 -I. -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/ruby-2.6.0-p0 -O3 -ggdb3 -Wall -Wextra -Wdeclaration-after-statement -Wdeprecated-declarations -Wdivision-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wmissing-noreturn -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wextra-tokens -pipe conftest.c -o conftest.i"
|
31
|
+
conftest.c:3:10: fatal error: 'vm_core.h' file not found
|
32
|
+
#include <vm_core.h>
|
33
|
+
^~~~~~~~~~~
|
34
|
+
1 error generated.
|
35
|
+
checked program was:
|
36
|
+
/* begin */
|
37
|
+
1: #include "ruby.h"
|
38
|
+
2:
|
39
|
+
3: #include <vm_core.h>
|
40
|
+
/* end */
|
41
|
+
|
42
|
+
--------------------
|
43
|
+
|
44
|
+
have_header: checking for vm_core.h... -------------------- yes
|
45
|
+
|
46
|
+
"clang -E -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/x86_64-darwin16 -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/ruby/backward -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0 -I. -I/Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0 -O3 -ggdb3 -Wall -Wextra -Wdeclaration-after-statement -Wdeprecated-declarations -Wdivision-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wmissing-noreturn -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wextra-tokens -pipe conftest.c -o conftest.i"
|
47
|
+
In file included from conftest.c:3:
|
48
|
+
In file included from /Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0/vm_core.h:75:
|
49
|
+
In file included from /Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0/method.h:14:
|
50
|
+
/Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0/internal.h:125:10: warning: '__msan_allocated_memory' macro redefined [-Wmacro-redefined]
|
51
|
+
# define __msan_allocated_memory(x, y)
|
52
|
+
^
|
53
|
+
/Library/Developer/CommandLineTools/usr/lib/clang/9.0.0/include/sanitizer/msan_interface.h:113:9: note: previous definition is here
|
54
|
+
#define __msan_allocated_memory(data, size)
|
55
|
+
^
|
56
|
+
In file included from conftest.c:3:
|
57
|
+
In file included from /Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0/vm_core.h:75:
|
58
|
+
In file included from /Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0/method.h:14:
|
59
|
+
/Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0/internal.h:127:10: warning: '__msan_unpoison' macro redefined [-Wmacro-redefined]
|
60
|
+
# define __msan_unpoison(x, y)
|
61
|
+
^
|
62
|
+
/Library/Developer/CommandLineTools/usr/lib/clang/9.0.0/include/sanitizer/msan_interface.h:112:9: note: previous definition is here
|
63
|
+
#define __msan_unpoison(a, size)
|
64
|
+
^
|
65
|
+
2 warnings generated.
|
66
|
+
checked program was:
|
67
|
+
/* begin */
|
68
|
+
1: #include "ruby.h"
|
69
|
+
2:
|
70
|
+
3: #include <vm_core.h>
|
71
|
+
/* end */
|
72
|
+
|
73
|
+
--------------------
|
74
|
+
|
75
|
+
have_header: checking for iseq.h... -------------------- yes
|
76
|
+
|
77
|
+
"clang -E -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/x86_64-darwin16 -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/ruby/backward -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0 -I. -I/Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0 -O3 -ggdb3 -Wall -Wextra -Wdeclaration-after-statement -Wdeprecated-declarations -Wdivision-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wmissing-noreturn -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wextra-tokens -pipe conftest.c -o conftest.i"
|
78
|
+
checked program was:
|
79
|
+
/* begin */
|
80
|
+
1: #include "ruby.h"
|
81
|
+
2:
|
82
|
+
3: #include <iseq.h>
|
83
|
+
/* end */
|
84
|
+
|
85
|
+
--------------------
|
86
|
+
|
data/lib/blab.rb
CHANGED
@@ -1,12 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "../ext/blab_trace"
|
4
|
+
require_relative "blab/config"
|
5
|
+
require_relative "blab/formatter"
|
6
|
+
require_relative "blab/printer"
|
7
|
+
require_relative "blab/tracer"
|
8
|
+
|
3
9
|
module Blab
|
4
|
-
def
|
10
|
+
def self.included(base)
|
5
11
|
base.define_singleton_method(:blab) do |name|
|
6
12
|
old_m = base.instance_method(name)
|
13
|
+
|
7
14
|
base.send(:define_method, name) do |*args|
|
8
|
-
|
9
|
-
|
15
|
+
begin
|
16
|
+
blab_trace(Blab::Tracer.trace)
|
17
|
+
old_m.bind(self).call(*args)
|
18
|
+
ensure
|
19
|
+
blab_trace(nil)
|
20
|
+
Blab::Tracer.reset
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def with_blab
|
26
|
+
begin
|
27
|
+
blab_trace(Blab::Tracer.trace)
|
28
|
+
yield
|
29
|
+
ensure
|
30
|
+
blab_trace(nil)
|
31
|
+
Blab::Tracer.reset
|
10
32
|
end
|
11
33
|
end
|
12
34
|
end
|
data/lib/blab/config.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
|
5
|
+
module Blab
|
6
|
+
module Config
|
7
|
+
extend self
|
8
|
+
|
9
|
+
DATETIME_FORMAT = "%H:%M:%S.%L"
|
10
|
+
|
11
|
+
DEFAULT_OUTPUT = [
|
12
|
+
{ type: :time, order: 1, width: 12 },
|
13
|
+
{ type: :event, order: 2, width: 6 },
|
14
|
+
{ type: :file_lines, order: 3, width: 50 },
|
15
|
+
#{ type: :class_name, order: 4, width: 10 },
|
16
|
+
#{ type: :method_name, order: 5, width: 12 },
|
17
|
+
{ type: :ru_maxss, order: 4, width: 12 },
|
18
|
+
{ type: :code_lines, order: 5, width: 120 }
|
19
|
+
].freeze
|
20
|
+
|
21
|
+
attr_writer :logger,
|
22
|
+
:datetime_format,
|
23
|
+
:log_output,
|
24
|
+
:trace_c_calls,
|
25
|
+
:output_config,
|
26
|
+
:output_order,
|
27
|
+
:original_scope_only
|
28
|
+
|
29
|
+
def logger
|
30
|
+
@logger ||= begin
|
31
|
+
logger = Logger.new(log_output)
|
32
|
+
logger.formatter = proc { |severity, datetime, progname, msg| "#{msg}\n" }
|
33
|
+
logger
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def log_output
|
38
|
+
@log_output ||= STDOUT
|
39
|
+
end
|
40
|
+
|
41
|
+
def output_config
|
42
|
+
@output_config ||= (@output_order || DEFAULT_OUTPUT).sort_by { |h| h[:order] }.map! { |h| [h[:type], h[:width]] }
|
43
|
+
end
|
44
|
+
|
45
|
+
def datetime_format
|
46
|
+
@datetime_format ||= DATETIME_FORMAT
|
47
|
+
end
|
48
|
+
|
49
|
+
def trace_c_calls?
|
50
|
+
@trace_c_calls ||= false
|
51
|
+
end
|
52
|
+
|
53
|
+
def original_scope_only?
|
54
|
+
@original_scope_only ||= false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Blab
|
4
|
+
module Formatter
|
5
|
+
extend self
|
6
|
+
|
7
|
+
ELLIPSIS = "..."
|
8
|
+
MAX_LENGTH = 100
|
9
|
+
|
10
|
+
def format(object)
|
11
|
+
formatted = prepare_for_inspection(object).inspect
|
12
|
+
return formatted if formatted.length < MAX_LENGTH
|
13
|
+
|
14
|
+
beginning = truncate(formatted, 0, MAX_LENGTH / 2)
|
15
|
+
ending = truncate(formatted, -MAX_LENGTH / 2, -1)
|
16
|
+
"#{beginning}#{ELLIPSIS}#{ending}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def prepare_for_inspection(object)
|
20
|
+
case object
|
21
|
+
when Array
|
22
|
+
prepare_array(object)
|
23
|
+
when Hash
|
24
|
+
prepare_hash(object)
|
25
|
+
else
|
26
|
+
object
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def prepare_array(array)
|
31
|
+
array.map { |element| prepare_for_inspection(element) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def prepare_hash(input_hash)
|
35
|
+
input_hash.inject({}) do |output_hash, key_and_value|
|
36
|
+
key, value = key_and_value.map { |element| prepare_for_inspection(element) }
|
37
|
+
output_hash[key] = value
|
38
|
+
output_hash
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def truncate(str, start_ind, end_ind)
|
45
|
+
str[start_ind..end_ind].sub(/\e\[\d+$/, '')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/blab/printer.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Printer
|
4
|
+
DEFAULT_CLASS_NAME_WIDTH = 5
|
5
|
+
DEFAULT_CODE_LINES_WIDTH = 120
|
6
|
+
DEFAULT_EVENT_WIDTH = 6
|
7
|
+
DEFAULT_FILE_LINES_WIDTH = 60
|
8
|
+
DEFAULT_RU_MAXSS_WIDTH = 50
|
9
|
+
DEFAULT_METHOD_NAME_WIDTH = 10
|
10
|
+
DEFAULT_TIME_WIDTH = 12
|
11
|
+
|
12
|
+
PRINT_FIELDS = [
|
13
|
+
:class_name,
|
14
|
+
:event,
|
15
|
+
:method_name,
|
16
|
+
:time,
|
17
|
+
:ru_maxss
|
18
|
+
].freeze
|
19
|
+
|
20
|
+
attr_reader :config, :logger
|
21
|
+
|
22
|
+
def initialize(config, logger)
|
23
|
+
@config = config
|
24
|
+
@logger = logger
|
25
|
+
end
|
26
|
+
|
27
|
+
def print(options = {})
|
28
|
+
strings = config.map do |(type, width)|
|
29
|
+
send(type, options.merge(width: width))
|
30
|
+
end
|
31
|
+
|
32
|
+
config_length = config.length
|
33
|
+
final = strings.map { |e| e.first.length }.max.times.map do |i|
|
34
|
+
config_length.times.map do |j|
|
35
|
+
str = strings[j][0][i] || ""
|
36
|
+
# TODO: do not ljust the last element
|
37
|
+
config_length == (j + 1) ? str : str.ljust(strings[j][1])
|
38
|
+
end.join(" ")
|
39
|
+
end
|
40
|
+
logger.info(final.join("\n"))
|
41
|
+
end
|
42
|
+
|
43
|
+
def file_lines(options = {})
|
44
|
+
file = options[:file]
|
45
|
+
line = options[:line]
|
46
|
+
width = options[:width] || DEFAULT_FILE_LINES_WIDTH
|
47
|
+
["#{file}:#{line}".scan(/.{#{width}}|.+/), width]
|
48
|
+
end
|
49
|
+
|
50
|
+
def code_lines(options= {})
|
51
|
+
file = options[:file]
|
52
|
+
line = options[:line]
|
53
|
+
width = options[:width] || DEFAULT_CODE_LINES_WIDTH
|
54
|
+
[source_line(file, line).scan(/.{#{width}}|.+/), width]
|
55
|
+
end
|
56
|
+
|
57
|
+
PRINT_FIELDS.each do |name|
|
58
|
+
define_method(name) do |options = {}|
|
59
|
+
val = options[name]
|
60
|
+
width = options[:width] || const_get("DEFAULT_#{name.upcase}_WIDTH")
|
61
|
+
[val.scan(/.{#{width}}|.+/), width]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def reset_files
|
66
|
+
@files_map && @files_map.keys.each { |key| @files_map.delete(key) }
|
67
|
+
end
|
68
|
+
|
69
|
+
def files_map
|
70
|
+
@files_map ||= Hash.new do |h, f|
|
71
|
+
h[f] = File.readlines(f)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# TODO: show all relevant file-lines
|
76
|
+
def source_line(file, line)
|
77
|
+
begin
|
78
|
+
files_map[file][line - 1]
|
79
|
+
rescue
|
80
|
+
"source is unavailable"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/blab/tracer.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Blab
|
4
|
+
module Tracer
|
5
|
+
extend self
|
6
|
+
|
7
|
+
FILE_NAME = /.+\/blab\.rb$/
|
8
|
+
C_CALLS = ["c-call", "c-return"].freeze
|
9
|
+
|
10
|
+
def reset
|
11
|
+
printer.reset_files
|
12
|
+
@defined_vars = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def trace
|
16
|
+
proc do |event, file, line, method_name, context, class_name, ru_maxss|
|
17
|
+
next if file =~ FILE_NAME
|
18
|
+
next if skip_c_calls? && C_CALLS.include?(event)
|
19
|
+
next if original_scope_only? && !original_scope?(file, method_name, class_name)
|
20
|
+
|
21
|
+
context.local_variables.each do |v|
|
22
|
+
next unless context.local_variable_defined?(v)
|
23
|
+
|
24
|
+
val = context.local_variable_get(v)
|
25
|
+
old_v = defined_vars[v]
|
26
|
+
|
27
|
+
next if val == old_v
|
28
|
+
|
29
|
+
formatted_output(v, val)
|
30
|
+
defined_vars[v] = val
|
31
|
+
end
|
32
|
+
|
33
|
+
printer.print(
|
34
|
+
time: Time.now.strftime(datetime_format),
|
35
|
+
event: event,
|
36
|
+
file: file,
|
37
|
+
line: line,
|
38
|
+
method_name: method_name.to_s,
|
39
|
+
class_name: class_name.to_s,
|
40
|
+
# ru_maxss is in bytes on Mac OS X (Darwin), but in kilobytes on BSD and Linux
|
41
|
+
ru_maxss: ru_maxss.to_s
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def printer
|
49
|
+
@printer ||= Printer.new(Blab::Config.output_config, logger)
|
50
|
+
end
|
51
|
+
|
52
|
+
def logger
|
53
|
+
Blab::Config.logger
|
54
|
+
end
|
55
|
+
|
56
|
+
def datetime_format
|
57
|
+
Blab::Config.datetime_format
|
58
|
+
end
|
59
|
+
|
60
|
+
def formatted_output(key, val)
|
61
|
+
logger.info("Var......... #{key}=#{Blab::Formatter.format(val)}")
|
62
|
+
end
|
63
|
+
|
64
|
+
def defined_vars
|
65
|
+
@defined_vars ||= {}
|
66
|
+
end
|
67
|
+
|
68
|
+
def original_scope_only?
|
69
|
+
Blab::Config.original_scope_only?
|
70
|
+
end
|
71
|
+
|
72
|
+
def skip_c_calls?
|
73
|
+
!Blab::Config.trace_c_calls?
|
74
|
+
end
|
75
|
+
|
76
|
+
def original_scope?(file, method_name, class_name)
|
77
|
+
@original_file ||= file
|
78
|
+
@original_method_name ||= method_name
|
79
|
+
@orinal_class_name ||= class_name
|
80
|
+
|
81
|
+
@original_file == file &&
|
82
|
+
@original_method_name == method_name &&
|
83
|
+
@orinal_class_name == class_name
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/lib/blab/version.rb
CHANGED
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative "../../lib/blab"
|
3
|
+
require "set"
|
4
|
+
|
5
|
+
class Y
|
6
|
+
include Blab
|
7
|
+
|
8
|
+
blab def x(name, &block)
|
9
|
+
a = 15
|
10
|
+
b = 30
|
11
|
+
d, c = 12, 67
|
12
|
+
puts(name)
|
13
|
+
yo = z(2)
|
14
|
+
10.times do |i|
|
15
|
+
a += i
|
16
|
+
c = 8
|
17
|
+
end
|
18
|
+
se = Set.new
|
19
|
+
hello(
|
20
|
+
a,
|
21
|
+
a,
|
22
|
+
b
|
23
|
+
)
|
24
|
+
hsh = {
|
25
|
+
xx: 1,
|
26
|
+
a: 200,
|
27
|
+
z: 300
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def z(n)
|
32
|
+
7 + n
|
33
|
+
end
|
34
|
+
|
35
|
+
def hello(a, b, c)
|
36
|
+
puts(a)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Blab::Config.original_scope_only = true
|
41
|
+
|
42
|
+
class Test
|
43
|
+
include Blab
|
44
|
+
|
45
|
+
def shuffle(arr)
|
46
|
+
for n in 0...arr.size
|
47
|
+
targ = n + rand(arr.size - n)
|
48
|
+
arr[n], arr[targ] = arr[targ], arr[n] if n != targ
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def pairs(a, b)
|
53
|
+
with_blab do
|
54
|
+
a << "Insane"
|
55
|
+
shuffle(b)
|
56
|
+
end
|
57
|
+
b.each { |x| shuffle(a); a.each { |y| print y, " ", x, ".\n" } }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
Blab::Config.log_output = "blab.log"
|
61
|
+
|
62
|
+
Test.new.pairs(["Bored", "Curious"], ["cat", "frog"])
|
63
|
+
|
metadata
CHANGED
@@ -1,25 +1,52 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blab
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.1.pre.alpha
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yulia Oletskaya
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-05-
|
12
|
-
dependencies:
|
11
|
+
date: 2019-05-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: debase-ruby_core_source
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.10'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.10'
|
13
27
|
description: A debugging tool
|
14
28
|
email: yulia.oletskaya@gmail.com
|
15
29
|
executables: []
|
16
|
-
extensions:
|
30
|
+
extensions:
|
31
|
+
- ext/extconf.rb
|
17
32
|
extra_rdoc_files: []
|
18
33
|
files:
|
19
34
|
- LICENSE
|
20
35
|
- README.md
|
36
|
+
- ext/Makefile
|
37
|
+
- ext/blab_trace.bundle
|
38
|
+
- ext/blab_trace.c
|
39
|
+
- ext/blab_trace.o
|
40
|
+
- ext/extconf.h
|
41
|
+
- ext/extconf.rb
|
42
|
+
- ext/mkmf.log
|
21
43
|
- lib/blab.rb
|
44
|
+
- lib/blab/config.rb
|
45
|
+
- lib/blab/formatter.rb
|
46
|
+
- lib/blab/printer.rb
|
47
|
+
- lib/blab/tracer.rb
|
22
48
|
- lib/blab/version.rb
|
49
|
+
- test/support/test.rb
|
23
50
|
homepage: http://rubygems.org/gems/blab
|
24
51
|
licenses:
|
25
52
|
- MIT
|
@@ -35,13 +62,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
35
62
|
version: '0'
|
36
63
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
64
|
requirements:
|
38
|
-
- - "
|
65
|
+
- - ">"
|
39
66
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
67
|
+
version: 1.3.1
|
41
68
|
requirements: []
|
42
|
-
|
43
|
-
rubygems_version: 2.6.13
|
69
|
+
rubygems_version: 3.0.1
|
44
70
|
signing_key:
|
45
71
|
specification_version: 4
|
46
72
|
summary: Blab
|
47
|
-
test_files:
|
73
|
+
test_files:
|
74
|
+
- test/support/test.rb
|