blab 0.0.0 → 0.0.1.pre.alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
[](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
|