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. |