root / HServer / 00.Server / 00.Program / node_modules / dtrace-provider / README.md
이력 | 보기 | 이력해설 | 다운로드 (8.17 KB)
1 | 39 | HKM | # 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. |