root / HServer / 00.Server / 00.Program / node_modules / dtrace-provider / README.md
이력 | 보기 | 이력해설 | 다운로드 (8.17 KB)
1 |
# dtrace-provider - Native DTrace providers for Node.js apps. |
---|---|
2 |
|
3 |
This extension allows you to create native DTrace providers for your |
4 |
Node.js applications. That is, to create providers and probes which |
5 |
expose information specific to your application, rather than |
6 |
information about the node runtime. |
7 |
|
8 |
You could use this to expose high-level information about the inner |
9 |
workings of your application, or to create a specific context in which |
10 |
to look at information from other runtime or system-level providers. |
11 |
|
12 |
The provider is not created in the usual way, by declaring it and then |
13 |
changing the build process to include it, but instead dynamically at |
14 |
runtime. This is done entirely in-process, and there is no background |
15 |
compiler or [dtrace(1M)](https://illumos.org/man/1M/dtrace) invocation. |
16 |
The process creating the provider need not run as root. |
17 |
|
18 |
## INSTALL |
19 |
|
20 |
$ npm install dtrace-provider |
21 |
|
22 |
## EXAMPLE |
23 |
|
24 |
Here's a simple example of creating a provider: |
25 |
|
26 |
```javascript |
27 |
var d = require('dtrace-provider'); |
28 |
|
29 |
var dtp = d.createDTraceProvider("nodeapp"); |
30 |
var p1 = dtp.addProbe("probe1", "int", "int"); |
31 |
var p2 = dtp.addProbe("probe2", "char *"); |
32 |
dtp.enable(); |
33 |
``` |
34 |
|
35 |
Probes may be fired via the provider object: |
36 |
|
37 |
```javascript |
38 |
dtp.fire("probe1", function() { |
39 |
return [1, 2]; |
40 |
}); |
41 |
dtp.fire("probe2", function() { |
42 |
return ["hello, dtrace via provider", "foo"]; |
43 |
}); |
44 |
``` |
45 |
|
46 |
or via the probe objects themselves: |
47 |
|
48 |
```javascript |
49 |
p1.fire(function() { |
50 |
return [1, 2, 3, 4, 5, 6]; |
51 |
}); |
52 |
p2.fire(function() { |
53 |
return ["hello, dtrace via probe", "foo"]; |
54 |
}); |
55 |
``` |
56 |
|
57 |
Note that `.fire()` takes a callback that returns the arguments to be |
58 |
provided when the DTrace probe actually fires. This allows you to call |
59 |
`.fire()` unconditionally when you want to fire the probe, but the |
60 |
callback will be invoked only when the DTrace probe is actually |
61 |
enabled. This allows you to create probes whose arguments might be |
62 |
expensive to construct, and only do any work when the probe is |
63 |
actually enabled. (Examples might include converting a large object to |
64 |
a string representation or gathering large amounts of information.) |
65 |
|
66 |
In some cases, creating a new closure to pass to `.fire()` each time |
67 |
it's called may introduce unwanted overhead. For extremely |
68 |
CPU-intensive or memory-conscious workloads, you can avoid this by |
69 |
lifting the closures for your hot probes into an outer scope. You can |
70 |
then supply arguments to that function as additional arguments to |
71 |
`.fire()`. As an example, you can convert the following program: |
72 |
|
73 |
```javascript |
74 |
function manipulateObj(largeObj) { |
75 |
var count = 0; |
76 |
var name = null; |
77 |
... |
78 |
p1.fire(function () { |
79 |
return [count, keyToValue(name), JSON.stringify(largeObj)]; |
80 |
}); |
81 |
} |
82 |
``` |
83 |
|
84 |
Into this one: |
85 |
|
86 |
```javascript |
87 |
function f(a, b, c) { |
88 |
return [a, keyToValue(b), JSON.stringify(c)]; |
89 |
} |
90 |
|
91 |
function manipulateObj(largeObj) { |
92 |
var count = 0; |
93 |
var name = null; |
94 |
... |
95 |
p1.fire(f, count, name, largeObj); |
96 |
} |
97 |
``` |
98 |
|
99 |
Be careful to avoid passing `.fire()` additional arguments that are |
100 |
themselves expensive to construct, as that undermines the design goal |
101 |
here: minimizing the effect of disabled probes. |
102 |
|
103 |
This example creates a provider called "nodeapp", and adds two |
104 |
probes. It then enables the provider, at which point the provider |
105 |
becomes visible to DTrace. |
106 |
|
107 |
The probes are then fired, which produces this output: |
108 |
|
109 |
$ sudo dtrace -Z -n 'nodeapp*:::probe1{ trace(arg0); trace(arg1) }' \ |
110 |
-n 'nodeapp*:::probe2{ trace(copyinstr(arg0)); }' |
111 |
dtrace: description 'nodeapp*:::probe1' matched 0 probes |
112 |
dtrace: description 'nodeapp*:::probe2' matched 0 probes |
113 |
CPU ID FUNCTION:NAME |
114 |
1 123562 func:probe1 1 2 |
115 |
1 123563 func:probe2 hello, dtrace |
116 |
|
117 |
Arguments are captured by a callback only executed when the probe is |
118 |
enabled. This means you can do more expensive work to gather arguments. |
119 |
|
120 |
The maximum number of arguments supported is 32. |
121 |
|
122 |
Available argument types are "int", for integer numeric values, |
123 |
"char *" for strings, and "json" for objects rendered into JSON strings. |
124 |
|
125 |
Arguments typed as "json" will be created as "char *" probes in |
126 |
DTrace, but objects passed to these probe arguments will be |
127 |
automatically serialized to JSON before being passed to DTrace. This |
128 |
feature is best used in conjunction with the json() D subroutine, but |
129 |
is available whether or not the platform supports it. |
130 |
|
131 |
# create a json probe: |
132 |
|
133 |
var dtp = d.createDTraceProvider("nodeapp"); |
134 |
var p1 = dtp.addProbe("j1", "json"); |
135 |
dtp.enable(); |
136 |
p1.fire(function() { return { "foo": "bar" }; }); |
137 |
|
138 |
# on a platform supporting json(): |
139 |
|
140 |
$ sudo dtrace -Z -n 'nodeapp*:::j1{ this->j = copyinstr(arg0); \ |
141 |
trace(json(this->j, "foo")) }' |
142 |
dtrace: description 'nodeapp$target:::j1' matched 0 probes |
143 |
CPU ID FUNCTION:NAME |
144 |
0 68712 j1:j1 bar |
145 |
|
146 |
## PLATFORM SUPPORT |
147 |
|
148 |
This libusdt-based Node.JS module supports 64 and 32 bit processes on |
149 |
Mac OS X and Solaris-like systems such as illumos or SmartOS. As more |
150 |
platform support is added to libusdt, those platforms will be |
151 |
supported by this module. See libusdt's status at: |
152 |
|
153 |
https://github.com/chrisa/libusdt#readme |
154 |
|
155 |
When using Mac OS X, be aware that as of 10.11 (El Capitan), DTrace use |
156 |
is restricted, and you'll probably want to |
157 |
[disable SIP](http://internals.exposed/blog/dtrace-vs-sip.html) to |
158 |
effectively use DTrace. |
159 |
|
160 |
FreeBSD 10 and 11 are also supported, but you'll need to make sure that |
161 |
you have the DTrace headers installed in `/usr/src` otherwise libusdt |
162 |
won't be able to compile. You can |
163 |
[clone them using SVN](https://www.freebsd.org/doc/handbook/svn.html), |
164 |
or find the correct `src.txz` |
165 |
[here](http://ftp.freebsd.org/pub/FreeBSD/releases/) and extract that. |
166 |
Also note that FreeBSD 10 is restricted to only 4 working arguments per |
167 |
probe. |
168 |
|
169 |
Platforms not supporting DTrace (notably, Linux and Windows) may |
170 |
install this module without building libusdt, with a stub no-op |
171 |
implementation provided for compatibility. This allows cross-platform |
172 |
npm modules to embed probes and include a dependency on this module. |
173 |
|
174 |
GNU Make is required to build libusdt; the build scripts will look for |
175 |
gmake in `PATH` first, and then for make. |
176 |
|
177 |
### TROUBLESHOOTING BUILD ISSUES |
178 |
|
179 |
If compilation fails during installation on platforms with DTrace, then |
180 |
the library will fall back to the stub implementation that does nothing. |
181 |
To force an installation failure when compiling fails, set the environment |
182 |
variable `NODE_DTRACE_PROVIDER_REQUIRE` to `hard`: |
183 |
|
184 |
```shell |
185 |
$ NODE_DTRACE_PROVIDER_REQUIRE=hard npm install |
186 |
``` |
187 |
|
188 |
This will then show you the output of the build process so you can see at |
189 |
which point it's having an issue. Common issues are: |
190 |
|
191 |
- Missing a C/C++ compiler toolchain for your platform. |
192 |
- `python` is Python 3 instead of Python 2; run `npm config set python python2.7` |
193 |
(or similar) to set the Python binary npm uses. |
194 |
- On OS X you may need to agree to the XCode license if that's the compiler |
195 |
toolchain you're using. This will usually manifest with an error like |
196 |
`Agreeing to the Xcode/iOS license requires admin privileges, please re-run as root via sudo.` |
197 |
To accept the license, you can run `sudo xcodebuild -license`. |
198 |
|
199 |
Once you've found and fixed the issue, you can run `npm rebuild` to rerun |
200 |
the lifecycle scripts. |
201 |
|
202 |
## CAVEATS |
203 |
|
204 |
There is some overhead to probes, even when disabled. Probes are |
205 |
already using the "is-enabled" feature of DTrace to control execution |
206 |
of the arguments-gathering callback, but some work still needs to be |
207 |
done before that's checked. This overhead should not be a problem |
208 |
unless probes are placed in particularly hot code paths. |
209 |
|
210 |
## CONTRIBUTING |
211 |
|
212 |
To clone the project's source code: |
213 |
|
214 |
$ git clone --recursive https://github.com/chrisa/node-dtrace-provider.git |
215 |
|
216 |
For issues, please use the [GitHub issue tracker](https://github.com/chrisa/node-dtrace-provider/issues) |
217 |
linked to the repository. GitHub pull requests are very welcome. |
218 |
|
219 |
## RUNNING THE TESTS |
220 |
|
221 |
```shell |
222 |
$ npm install |
223 |
$ sudo ./node_modules/.bin/tap --tap test/*.test.js |
224 |
``` |
225 |
|
226 |
## OTHER IMPLEMENTATIONS |
227 |
|
228 |
This node extension is derived from the ruby-dtrace gem, via the Perl |
229 |
module Devel::DTrace::Provider, both of which provide the same |
230 |
functionality to those languages. |