ruby-dtrace-consumer 0.4.0
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.
- data/LICENCE +20 -0
- data/README.md +51 -0
- data/ext/Makefile +187 -0
- data/ext/dtrace_aggdata.c +132 -0
- data/ext/dtrace_aggdata.c~ +141 -0
- data/ext/dtrace_aggdata.o +0 -0
- data/ext/dtrace_api.bundle +0 -0
- data/ext/dtrace_api.c +102 -0
- data/ext/dtrace_api.c~ +113 -0
- data/ext/dtrace_api.h +138 -0
- data/ext/dtrace_api.h~ +155 -0
- data/ext/dtrace_api.o +0 -0
- data/ext/dtrace_bufdata.c +130 -0
- data/ext/dtrace_bufdata.c~ +139 -0
- data/ext/dtrace_bufdata.o +0 -0
- data/ext/dtrace_dropdata.c +121 -0
- data/ext/dtrace_dropdata.c~ +131 -0
- data/ext/dtrace_dropdata.o +0 -0
- data/ext/dtrace_errdata.c +100 -0
- data/ext/dtrace_errdata.c~ +110 -0
- data/ext/dtrace_errdata.o +0 -0
- data/ext/dtrace_hdl.c +677 -0
- data/ext/dtrace_hdl.c~ +689 -0
- data/ext/dtrace_hdl.o +0 -0
- data/ext/dtrace_probedata.c +273 -0
- data/ext/dtrace_probedata.c~ +283 -0
- data/ext/dtrace_probedata.o +0 -0
- data/ext/dtrace_probedesc.c +93 -0
- data/ext/dtrace_probedesc.c~ +78 -0
- data/ext/dtrace_probedesc.o +0 -0
- data/ext/dtrace_process.c +44 -0
- data/ext/dtrace_process.c~ +56 -0
- data/ext/dtrace_process.o +0 -0
- data/ext/dtrace_program.c +52 -0
- data/ext/dtrace_program.c~ +62 -0
- data/ext/dtrace_program.o +0 -0
- data/ext/dtrace_programinfo.c +70 -0
- data/ext/dtrace_programinfo.c~ +60 -0
- data/ext/dtrace_programinfo.o +0 -0
- data/ext/dtrace_recdesc.c +37 -0
- data/ext/dtrace_recdesc.c~ +46 -0
- data/ext/dtrace_recdesc.o +0 -0
- data/ext/dtrace_util.c +92 -0
- data/ext/dtrace_util.o +0 -0
- data/ext/extconf.rb +7 -0
- data/lib/dtrace.rb +95 -0
- data/lib/dtrace/aggregate.rb +40 -0
- data/lib/dtrace/aggregateset.rb +19 -0
- data/lib/dtrace/consumer.rb +174 -0
- data/lib/dtrace/data.rb +85 -0
- data/lib/dtrace/dof.rb +8 -0
- data/lib/dtrace/printfrecord.rb +10 -0
- data/lib/dtrace/probedata.rb +23 -0
- data/lib/dtrace/probedesc.rb +15 -0
- data/lib/dtrace/record.rb +11 -0
- data/lib/dtrace/stackrecord.rb +31 -0
- data/lib/dtrace/tracer.rb +35 -0
- data/lib/dtrace/version.rb +8 -0
- data/lib/dtrace/version.rb~ +8 -0
- data/lib/dtraceconsumer.rb +9 -0
- data/test/test_aggregates.rb +45 -0
- data/test/test_drops_errors.rb +166 -0
- data/test/test_dtrace.rb +155 -0
- data/test/test_gc.rb +11 -0
- data/test/test_helper.rb +20 -0
- data/test/test_helper.rb~ +16 -0
- data/test/test_legacy_consumer.rb +47 -0
- data/test/test_probedata.rb +30 -0
- data/test/test_processes.rb +66 -0
- data/test/test_profile.rb +198 -0
- data/test/test_repeat.rb +50 -0
- data/test/test_rubyprobe.rb +52 -0
- data/test/test_rubyprobe.rb~ +52 -0
- data/test/test_typefilter.rb +94 -0
- metadata +121 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
/* Ruby-DTrace
|
2
|
+
* (c) 2007 Chris Andrews <chris@nodnol.org>
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include "dtrace_api.h"
|
6
|
+
|
7
|
+
/* :nodoc: */
|
8
|
+
VALUE dtraceprograminfo_init(VALUE self)
|
9
|
+
{
|
10
|
+
dtrace_proginfo_t *proginfo;
|
11
|
+
|
12
|
+
Data_Get_Struct(self, dtrace_proginfo_t, proginfo);
|
13
|
+
return self;
|
14
|
+
}
|
15
|
+
|
16
|
+
/*
|
17
|
+
* Returns the number of aggregates associated with this program.
|
18
|
+
*/
|
19
|
+
VALUE dtraceprograminfo_aggregates_count(VALUE self)
|
20
|
+
{
|
21
|
+
dtrace_proginfo_t *proginfo;
|
22
|
+
|
23
|
+
Data_Get_Struct(self, dtrace_proginfo_t, proginfo);
|
24
|
+
return INT2NUM(proginfo->dpi_aggregates);
|
25
|
+
}
|
26
|
+
|
27
|
+
/*
|
28
|
+
* Returns the number of record generating probes associated with this
|
29
|
+
* program.
|
30
|
+
*/
|
31
|
+
VALUE dtraceprograminfo_recgens_count(VALUE self)
|
32
|
+
{
|
33
|
+
dtrace_proginfo_t *proginfo;
|
34
|
+
|
35
|
+
Data_Get_Struct(self, dtrace_proginfo_t, proginfo);
|
36
|
+
return INT2NUM(proginfo->dpi_recgens);
|
37
|
+
}
|
38
|
+
|
39
|
+
/*
|
40
|
+
* Returns the number of probes matched by this program.
|
41
|
+
*/
|
42
|
+
VALUE dtraceprograminfo_matches_count(VALUE self)
|
43
|
+
{
|
44
|
+
dtrace_proginfo_t *proginfo;
|
45
|
+
|
46
|
+
Data_Get_Struct(self, dtrace_proginfo_t, proginfo);
|
47
|
+
return INT2NUM(proginfo->dpi_matches);
|
48
|
+
}
|
49
|
+
|
50
|
+
/*
|
51
|
+
* Returns the number of speculations specified by this program.
|
52
|
+
*/
|
53
|
+
VALUE dtraceprograminfo_speculations_count(VALUE self)
|
54
|
+
{
|
55
|
+
dtrace_proginfo_t *proginfo;
|
56
|
+
|
57
|
+
Data_Get_Struct(self, dtrace_proginfo_t, proginfo);
|
58
|
+
return INT2NUM(proginfo->dpi_speculations);
|
59
|
+
}
|
60
|
+
|
Binary file
|
@@ -0,0 +1,37 @@
|
|
1
|
+
/* Ruby-DTrace
|
2
|
+
* (c) 2007 Chris Andrews <chris@nodnol.org>
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include "dtrace_api.h"
|
6
|
+
|
7
|
+
/*
|
8
|
+
* Returns the type of action which generated this recdesc.
|
9
|
+
* (exit, printf, printa or "other" for all other actions).
|
10
|
+
*/
|
11
|
+
VALUE dtracerecdesc_action(VALUE self)
|
12
|
+
{
|
13
|
+
dtrace_recdesc_t *recdesc;
|
14
|
+
VALUE v;
|
15
|
+
Data_Get_Struct(self, dtrace_recdesc_t, recdesc);
|
16
|
+
|
17
|
+
if (recdesc){
|
18
|
+
switch (recdesc->dtrd_action) {
|
19
|
+
case DTRACEACT_EXIT:
|
20
|
+
v = rb_str_new2("exit");
|
21
|
+
break;
|
22
|
+
case DTRACEACT_PRINTF:
|
23
|
+
v = rb_str_new2("printf");
|
24
|
+
break;
|
25
|
+
case DTRACEACT_PRINTA:
|
26
|
+
v = rb_str_new2("printa");
|
27
|
+
break;
|
28
|
+
default:
|
29
|
+
v = rb_str_new2("other");
|
30
|
+
break;
|
31
|
+
}
|
32
|
+
return v;
|
33
|
+
}
|
34
|
+
else {
|
35
|
+
return Qnil;
|
36
|
+
}
|
37
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
/* Ruby-DTrace
|
2
|
+
* (c) 2007 Chris Andrews <chris@nodnol.org>
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include "dtrace_api.h"
|
6
|
+
|
7
|
+
/* :nodoc: */
|
8
|
+
VALUE dtracerecdesc_init(VALUE self)
|
9
|
+
{
|
10
|
+
dtrace_recdesc_t *recdesc;
|
11
|
+
|
12
|
+
Data_Get_Struct(self, dtrace_recdesc_t, recdesc);
|
13
|
+
return self;
|
14
|
+
}
|
15
|
+
|
16
|
+
/*
|
17
|
+
* Returns the type of action which generated this recdesc.
|
18
|
+
* (exit, printf, printa or "other" for all other actions).
|
19
|
+
*/
|
20
|
+
VALUE dtracerecdesc_action(VALUE self)
|
21
|
+
{
|
22
|
+
dtrace_recdesc_t *recdesc;
|
23
|
+
VALUE v;
|
24
|
+
Data_Get_Struct(self, dtrace_recdesc_t, recdesc);
|
25
|
+
|
26
|
+
if (recdesc){
|
27
|
+
switch (recdesc->dtrd_action) {
|
28
|
+
case DTRACEACT_EXIT:
|
29
|
+
v = rb_str_new2("exit");
|
30
|
+
break;
|
31
|
+
case DTRACEACT_PRINTF:
|
32
|
+
v = rb_str_new2("printf");
|
33
|
+
break;
|
34
|
+
case DTRACEACT_PRINTA:
|
35
|
+
v = rb_str_new2("printa");
|
36
|
+
break;
|
37
|
+
default:
|
38
|
+
v = rb_str_new2("other");
|
39
|
+
break;
|
40
|
+
}
|
41
|
+
return v;
|
42
|
+
}
|
43
|
+
else {
|
44
|
+
return Qnil;
|
45
|
+
}
|
46
|
+
}
|
Binary file
|
data/ext/dtrace_util.c
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
/* Ruby-DTrace
|
2
|
+
* (c) 2007 Chris Andrews <chris@nodnol.org>
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include "dtrace_api.h"
|
6
|
+
#include <ctype.h>
|
7
|
+
|
8
|
+
RUBY_EXTERN VALUE eDTraceException;
|
9
|
+
|
10
|
+
/*
|
11
|
+
* Most of this function lifted from libdtrace/common/dt_consume.c
|
12
|
+
* dt_print_bytes().
|
13
|
+
*/
|
14
|
+
VALUE handle_bytedata(caddr_t addr, uint32_t nbytes)
|
15
|
+
{
|
16
|
+
/*
|
17
|
+
* If the byte stream is a series of printable characters, followed by
|
18
|
+
* a terminating byte, we print it out as a string. Otherwise, we
|
19
|
+
* assume that it's something else and just print the bytes.
|
20
|
+
*/
|
21
|
+
int i, j;
|
22
|
+
char *c = addr;
|
23
|
+
|
24
|
+
VALUE robj;
|
25
|
+
|
26
|
+
if (nbytes == 0) {
|
27
|
+
return rb_str_new2("");
|
28
|
+
}
|
29
|
+
|
30
|
+
for (i = 0; i < nbytes; i++) {
|
31
|
+
/*
|
32
|
+
* We define a "printable character" to be one for which
|
33
|
+
* isprint(3C) returns non-zero, isspace(3C) returns non-zero,
|
34
|
+
* or a character which is either backspace or the bell.
|
35
|
+
* Backspace and the bell are regrettably special because
|
36
|
+
* they fail the first two tests -- and yet they are entirely
|
37
|
+
* printable. These are the only two control characters that
|
38
|
+
* have meaning for the terminal and for which isprint(3C) and
|
39
|
+
* isspace(3C) return 0.
|
40
|
+
*/
|
41
|
+
if (isprint(c[i]) || isspace(c[i]) ||
|
42
|
+
c[i] == '\b' || c[i] == '\a')
|
43
|
+
continue;
|
44
|
+
|
45
|
+
if (c[i] == '\0' && i > 0) {
|
46
|
+
/*
|
47
|
+
* This looks like it might be a string. Before we
|
48
|
+
* assume that it is indeed a string, check the
|
49
|
+
* remainder of the byte range; if it contains
|
50
|
+
* additional non-nul characters, we'll assume that
|
51
|
+
* it's a binary stream that just happens to look like
|
52
|
+
* a string.
|
53
|
+
*/
|
54
|
+
for (j = i + 1; j < nbytes; j++) {
|
55
|
+
if (c[j] != '\0')
|
56
|
+
break;
|
57
|
+
}
|
58
|
+
|
59
|
+
if (j != nbytes)
|
60
|
+
break;
|
61
|
+
|
62
|
+
/* It's a string */
|
63
|
+
return (rb_str_new2((char *)addr));
|
64
|
+
}
|
65
|
+
|
66
|
+
break;
|
67
|
+
}
|
68
|
+
|
69
|
+
if (i == nbytes) {
|
70
|
+
/*
|
71
|
+
* The byte range is all printable characters, but there is
|
72
|
+
* no trailing nul byte. We'll assume that it's a string.
|
73
|
+
*/
|
74
|
+
char *s = malloc(nbytes + 1);
|
75
|
+
if (!s) {
|
76
|
+
rb_raise(eDTraceException, "out of memory: failed to allocate string value");
|
77
|
+
return (Qnil);
|
78
|
+
}
|
79
|
+
(void) strncpy(s, c, nbytes);
|
80
|
+
s[nbytes] = '\0';
|
81
|
+
robj = rb_str_new2(s);
|
82
|
+
free(s);
|
83
|
+
return (robj);
|
84
|
+
}
|
85
|
+
|
86
|
+
/* return byte array */
|
87
|
+
robj = rb_ary_new();
|
88
|
+
for (i = 0; i < nbytes; i++)
|
89
|
+
rb_ary_push(robj, INT2FIX(addr[i]));
|
90
|
+
|
91
|
+
return (robj);
|
92
|
+
}
|
data/ext/dtrace_util.o
ADDED
Binary file
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
require 'rbconfig'
|
3
|
+
|
4
|
+
# Need to specify full path to dtrace.h or we'll pick up ruby's
|
5
|
+
# dtrace.h on Solaris or other builds with the runtime probes included.
|
6
|
+
have_library("dtrace", "dtrace_open", "/usr/include/dtrace.h")
|
7
|
+
create_makefile("dtrace_api")
|
data/lib/dtrace.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
#
|
2
|
+
# Ruby-DTrace
|
3
|
+
# (c) 2007 Chris Andrews <chris@nodnol.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
require 'dtrace_api'
|
7
|
+
require 'dtrace/record'
|
8
|
+
require 'dtrace/consumer'
|
9
|
+
require 'dtraceconsumer'
|
10
|
+
require 'dtrace/aggregate'
|
11
|
+
require 'dtrace/aggregateset'
|
12
|
+
require 'dtrace/probedata'
|
13
|
+
require 'dtrace/probedesc'
|
14
|
+
require 'dtrace/stackrecord'
|
15
|
+
require 'dtrace/printfrecord'
|
16
|
+
require 'dtrace/data'
|
17
|
+
require 'dtrace/version'
|
18
|
+
|
19
|
+
# A DTrace handle. Provides methods for inspecting available probes,
|
20
|
+
# compiling and running programs, and for setting up callbacks to
|
21
|
+
# receive trace data.
|
22
|
+
#
|
23
|
+
# The general structure of a DTrace-based program is:
|
24
|
+
#
|
25
|
+
# * Create a handle with DTrace.new
|
26
|
+
# * Set options
|
27
|
+
# * Compile the program, possibly inspecting the return DTrace::ProgramInfo
|
28
|
+
# * Execute the program
|
29
|
+
# * Start tracing
|
30
|
+
# * Consume data, either directly by setting up callbacks, or using a DTrace::Consumer.
|
31
|
+
# * Stop tracing
|
32
|
+
#
|
33
|
+
# === Listing probes
|
34
|
+
#
|
35
|
+
# d.each_probe do |p|
|
36
|
+
# puts "#{p.provider}:#{p.mod}:#{p.func}:#{p.name}"
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# === Setting options
|
40
|
+
#
|
41
|
+
# d.setopt("bufsize", "8m")
|
42
|
+
# d.setopt("aggsize", "4m")
|
43
|
+
# d.setopt("stackframes", "5")
|
44
|
+
# d.setopt("strsize", "131072")
|
45
|
+
#
|
46
|
+
# === Compiling a program
|
47
|
+
#
|
48
|
+
# d.compile "syscall:::entry { trace(execname); stack(); }"
|
49
|
+
# d.execute
|
50
|
+
#
|
51
|
+
# === Setting up callbacks
|
52
|
+
#
|
53
|
+
# d.buf_consumer(prob {|buf| yield buf })
|
54
|
+
# d.work(proc {|probe| yield probe }, proc {|rec| yield rec })
|
55
|
+
#
|
56
|
+
# === Creating a process
|
57
|
+
#
|
58
|
+
# p = t.createprocess([ '/usr/bin/true' ])
|
59
|
+
# t.go
|
60
|
+
# p.continue
|
61
|
+
#
|
62
|
+
# c = DTrace::Consumer.new(t)
|
63
|
+
# c.consume do |d|
|
64
|
+
# ..
|
65
|
+
# end
|
66
|
+
|
67
|
+
class DTrace
|
68
|
+
STATUS_NONE = 0
|
69
|
+
STATUS_OKAY = 1
|
70
|
+
STATUS_EXITED = 2
|
71
|
+
STATUS_FILLED = 3
|
72
|
+
STATUS_STOPPED = 4
|
73
|
+
|
74
|
+
# Yields each probe on the system, optionally matching against a
|
75
|
+
# probe specification:
|
76
|
+
#
|
77
|
+
# e.g.
|
78
|
+
# syscall::: -> all probes in the syscall provider
|
79
|
+
# pid123:::return -> all return probes in pid 123.
|
80
|
+
#
|
81
|
+
def each_probe(match=nil, &block)
|
82
|
+
if match
|
83
|
+
parts = match.split(':', 4)
|
84
|
+
begin
|
85
|
+
each_probe_match(*parts, &block)
|
86
|
+
rescue ArgumentError => e
|
87
|
+
raise DTrace::Exception.new("each_probe: probe specification expected (e.g. 'provider:::')")
|
88
|
+
end
|
89
|
+
else
|
90
|
+
each_probe_all(&block)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#
|
2
|
+
# Ruby-DTrace
|
3
|
+
# (c) 2007 Chris Andrews <chris@nodnol.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
# Represents an aggregation record built from a series of
|
7
|
+
# DTraceAggData records.
|
8
|
+
#
|
9
|
+
# Intended to to built up by calling +add_record+ repeatedly with
|
10
|
+
# DTrace::AggData objects until a completed DTrace::Aggregate is
|
11
|
+
# returned. (until a complete record is available, +add_record+
|
12
|
+
# returns nil).
|
13
|
+
#
|
14
|
+
# See consumer.rb for an example of this.
|
15
|
+
class DTrace
|
16
|
+
class Aggregate
|
17
|
+
attr_reader :value, :tuple
|
18
|
+
|
19
|
+
# Create an empty DTrace::Aggregate: use +add_record+ to add data.
|
20
|
+
def initialize
|
21
|
+
@tuple = Array.new
|
22
|
+
end
|
23
|
+
|
24
|
+
# Add a DTrace::AggData record to this aggregate. Returns nil until it
|
25
|
+
# receives a record of aggtype "last", when it returns the complete
|
26
|
+
# DTrace::Aggregate.
|
27
|
+
def add_record(r)
|
28
|
+
case r.aggtype
|
29
|
+
when "tuple"
|
30
|
+
@tuple << r.value
|
31
|
+
when "value"
|
32
|
+
@value = r.value
|
33
|
+
when "last"
|
34
|
+
return self
|
35
|
+
end
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
#
|
2
|
+
# Ruby-DTrace
|
3
|
+
# (c) 2007 Chris Andrews <chris@nodnol.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
# A DTrace::Consumer provides access to the data produced by the running
|
7
|
+
# D program. Having compiled and executed a D program, you typically
|
8
|
+
# create a DTrace::Consumer, and wait for data.
|
9
|
+
#
|
10
|
+
# You can either wait indefinitely for data, or consume all the data
|
11
|
+
# waiting and then stop: if your D program consists of only of
|
12
|
+
# aggregations, returned by printa() actions in the END block, this
|
13
|
+
# will be the best approach. If you have a mix of trace() and printf()
|
14
|
+
# actions elsewhere, you'll probably want to wait until interrupted,
|
15
|
+
# the D program itself exits, or your program decides it has collected
|
16
|
+
# enough data.
|
17
|
+
#
|
18
|
+
# The two approaches are implemented by the +consume+ and
|
19
|
+
# +consume_once+ methods.
|
20
|
+
#
|
21
|
+
# The +consume+ and +consume_once+ methods accept a block to which is
|
22
|
+
# yielded complete DTrace::Data objects, one for each probe which fires.
|
23
|
+
#
|
24
|
+
# You must have already started tracing when you call +consume+ or
|
25
|
+
# +consume_once+, so the general structure will look like:
|
26
|
+
#
|
27
|
+
# t = DTrace.new
|
28
|
+
# progtext = "..."
|
29
|
+
# prog = t.compile progtext
|
30
|
+
# prog.execute
|
31
|
+
# t.go
|
32
|
+
# c = DTrace::Consumer.new(t)
|
33
|
+
# c.consume_once do |d|
|
34
|
+
# # handle DTrace::Data objects
|
35
|
+
# # ...
|
36
|
+
# # get bored:
|
37
|
+
# c.finish
|
38
|
+
# end
|
39
|
+
|
40
|
+
class DTrace
|
41
|
+
class Consumer
|
42
|
+
|
43
|
+
def initialize(t)
|
44
|
+
@t = t
|
45
|
+
@done = false
|
46
|
+
@types = []
|
47
|
+
|
48
|
+
@drophandler = nil
|
49
|
+
@errhandler = nil
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
# The consumer callbacks:
|
55
|
+
#
|
56
|
+
# DTraceRecDesc -> rec_consumer
|
57
|
+
# DTraceProbeData -> probe_consumer
|
58
|
+
# DTraceBufData -> buf_consumer
|
59
|
+
#
|
60
|
+
# We expect a sequence of calls to these procs, and we accumulate
|
61
|
+
# data in the @curr DTrace::Data based on this:
|
62
|
+
#
|
63
|
+
# DTrace::ProbeData (initial callback for a probe firing)
|
64
|
+
# DTrace::RecDesc
|
65
|
+
# ...
|
66
|
+
# DTrace::RecDesc = nil (end of data)
|
67
|
+
#
|
68
|
+
|
69
|
+
def rec_consumer(block)
|
70
|
+
proc do |rec|
|
71
|
+
if rec
|
72
|
+
@curr.add_recdata(rec)
|
73
|
+
else
|
74
|
+
@curr.finish
|
75
|
+
block.call(@curr)
|
76
|
+
@curr = DTrace::Data.new(@types)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def probe_consumer
|
82
|
+
proc do |probe|
|
83
|
+
@curr.add_probedata(probe)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def buf_consumer
|
88
|
+
proc do |buf|
|
89
|
+
@curr.add_bufdata(buf)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def filter_types(types)
|
94
|
+
@types = types
|
95
|
+
@curr = DTrace::Data.new(types)
|
96
|
+
end
|
97
|
+
|
98
|
+
public
|
99
|
+
|
100
|
+
# Provide a proc which will be executed when a drop record is
|
101
|
+
# received.
|
102
|
+
def drophandler(&block)
|
103
|
+
@drophandler = block
|
104
|
+
@t.drop_consumer(proc do |drop|
|
105
|
+
if @drophandler
|
106
|
+
@drophandler.call(drop)
|
107
|
+
end
|
108
|
+
end)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Provide a proc which will be executed when an error record is
|
112
|
+
# received.
|
113
|
+
def errhandler(&block)
|
114
|
+
@errhandler = block
|
115
|
+
@t.err_consumer(proc do |err|
|
116
|
+
if @errhandler
|
117
|
+
@errhandler.call(err)
|
118
|
+
end
|
119
|
+
end)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Signals that the client wishes to stop consuming trace data.
|
123
|
+
def finish
|
124
|
+
@t.stop
|
125
|
+
@done = true
|
126
|
+
end
|
127
|
+
|
128
|
+
# Waits for data from the D program, and yields the records returned
|
129
|
+
# to the block given. Returns when the D program exits.
|
130
|
+
#
|
131
|
+
# Pass a list of classes to restrict the types of data returned,
|
132
|
+
# from:
|
133
|
+
#
|
134
|
+
# * DTraceRecord
|
135
|
+
# * DTracePrintfRecord
|
136
|
+
# * DTraceAggregateSet
|
137
|
+
# * DTraceStackRecord
|
138
|
+
#
|
139
|
+
def consume(*types, &block)
|
140
|
+
filter_types(types)
|
141
|
+
@t.buf_consumer(buf_consumer)
|
142
|
+
begin
|
143
|
+
while(true) do
|
144
|
+
@t.sleep
|
145
|
+
work = @t.work(probe_consumer, rec_consumer(block))
|
146
|
+
if (@done || work > 0)
|
147
|
+
break
|
148
|
+
end
|
149
|
+
end
|
150
|
+
ensure
|
151
|
+
@t.stop
|
152
|
+
@t.work(probe_consumer)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Yields the data waiting from the current program, then returns.
|
157
|
+
#
|
158
|
+
# Pass a list of classes to restrict the types of data returned,
|
159
|
+
# from:
|
160
|
+
#
|
161
|
+
# * DTraceRecord
|
162
|
+
# * DTracePrintfRecord
|
163
|
+
# * DTraceAggregateSet
|
164
|
+
# * DTraceStackRecord
|
165
|
+
#
|
166
|
+
def consume_once(*types, &block)
|
167
|
+
filter_types(types)
|
168
|
+
@t.buf_consumer(buf_consumer)
|
169
|
+
@t.stop
|
170
|
+
@t.work(probe_consumer, rec_consumer(block))
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
end
|