├── .editorconfig
├── .eslintrc
├── .gitignore
├── .idea
└── runConfigurations
│ ├── Promise_context_convention.xml
│ ├── async_context_test_js.xml
│ ├── bind_emitter_multiple_tap_js.xml
│ ├── bind_emitter_tap_js.xml
│ ├── cls_with_net_connection_2.xml
│ ├── cls_with_net_connection_value_newContextValue.xml
│ ├── dns_tap_js.xml
│ ├── fs_tap_js.xml
│ ├── http_events_test_js.xml
│ ├── interleave_contexts_tap_js.xml
│ ├── namespaces_multiple_values_specs_js.xml
│ ├── namespaces_multiple_values_tap_js.xml
│ ├── namespaces_spec_js.xml
│ ├── namespaces_tap_js.xml
│ ├── nesting_tap_js.xml
│ ├── net_events_spec_js.xml
│ ├── net_events_tap_js.xml
│ ├── net_events_test_js.xml
│ ├── npm_test.xml
│ ├── npm_test_mocha.xml
│ ├── promise_context_convention_spec_js.xml
│ ├── promises_tap_js.xml
│ ├── proper_exit_tap_js.xml
│ ├── run_tap_tests.xml
│ ├── test_async_context_test_js.xml
│ ├── test_net_events_test_js.xml
│ └── with_http_server_and_client_request.xml
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── context-legacy.js
├── context.js
├── index.js
├── logs
├── async-hook-passing.log
├── async-hook.log
├── async-hook_using_parentid.log
├── async-listener.log
├── http-agent.log
├── namespaces-multiple-values.specs.log
└── providers.json
├── package-lock.json
├── package.json
└── test
├── async-context.test.js
├── async-no-run-queue-multiple.test.js
├── http-agent-break.test.js
├── http-events.test.js
├── namespaces-multiple-values.test.js
├── namespaces.test.js
├── net-events.test.js
├── net-events2.test.js
├── promise-context-convention.spec.js
└── tap
├── async-context.tap.js
├── async-no-run-queue-multiple.tap.js
├── bind-emitter-multiple.tap.js
├── bind-emitter.tap.js
├── bind.tap.js
├── crypto.tap.js
├── dns.tap.js
├── error-handling.tap.js
├── fs.tap.js
├── interleave-contexts.tap.js
├── namespaces-multiple-values.tap.js
├── namespaces.tap.js
├── nesting.tap.js
├── net-events.tap.js
├── promises.tap.js
├── proper-exit.tap.js
├── run-and-return.tap.js
├── simple.tap.js
├── timers.tap.js
├── tracer-scenarios.tap.js
└── zlib.tap.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | end_of_line = lf
9 | insert_final_newline = true
10 | trim_trailing_whitespace = true
11 |
12 | [*.json]
13 | indent_style = space
14 | indent_size = 2
15 |
16 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "node": true,
4 | "mocha": true,
5 | "es6": true
6 | },
7 | "rules": {
8 | "curly": 0,
9 | "no-lonely-if": 1,
10 | "no-mixed-requires": 0,
11 | "no-underscore-dangle": 0,
12 | "no-unused-vars": [2, {
13 | "vars": "all",
14 | "args": "after-used"
15 | }],
16 | "no-use-before-define": [2, "nofunc"],
17 | "quotes": 0,
18 | "semi": [2, "always"],
19 | "space-infix-ops": 0,
20 | "strict": 0,
21 | "max-len": [1, 160, 2]
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .idea/*
3 | !.idea/runConfigurations/
4 | npm-debug.log
5 | .vscode
6 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Promise_context_convention.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | project
4 |
5 | $PROJECT_DIR$/node_modules/mocha
6 | $PROJECT_DIR$
7 | true
8 |
9 |
10 |
11 |
12 | bdd
13 |
14 | SUITE
15 | $PROJECT_DIR$/test/promise-context-convention.spec.js
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/async_context_test_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | project
4 |
5 | $PROJECT_DIR$/node_modules/mocha
6 | $PROJECT_DIR$
7 | true
8 | bdd
9 |
10 | TEST_FILE
11 | $PROJECT_DIR$/test/async-context.test.js
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/bind_emitter_multiple_tap_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/bind_emitter_tap_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
10 |
13 |
14 |
15 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/cls_with_net_connection_2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | project
4 |
5 | $PROJECT_DIR$/node_modules/mocha
6 | $PROJECT_DIR$
7 | true
8 |
9 |
10 |
11 |
12 | bdd
13 |
14 | SUITE
15 | $PROJECT_DIR$/test/net-events2.test.js
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/cls_with_net_connection_value_newContextValue.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | project
4 |
5 | $PROJECT_DIR$/node_modules/mocha
6 | $PROJECT_DIR$
7 | true
8 |
9 |
10 |
11 |
12 | bdd
13 |
14 | TEST
15 | $PROJECT_DIR$/test/net-events.test.js
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/dns_tap_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/fs_tap_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
13 |
16 |
17 |
18 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/http_events_test_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | project
4 |
5 | $PROJECT_DIR$/node_modules/mocha
6 | $PROJECT_DIR$
7 | true
8 | bdd
9 |
10 | TEST_FILE
11 | $PROJECT_DIR$/test/http-events.test.js
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/interleave_contexts_tap_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/namespaces_multiple_values_specs_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | project
4 |
5 | $PROJECT_DIR$/node_modules/mocha
6 | $PROJECT_DIR$
7 | true
8 | bdd
9 |
10 | TEST_FILE
11 | $PROJECT_DIR$/test/namespaces-multiple-values.test.js
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/namespaces_multiple_values_tap_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/namespaces_spec_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | project
4 |
5 | $PROJECT_DIR$/node_modules/mocha
6 | $PROJECT_DIR$
7 | true
8 | bdd
9 |
10 | TEST_FILE
11 | $PROJECT_DIR$/test/namespaces.test.js
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/namespaces_tap_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
10 |
13 |
14 |
15 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/nesting_tap_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/net_events_spec_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | project
4 |
5 | $PROJECT_DIR$/node_modules/mocha
6 | $PROJECT_DIR$
7 | true
8 | bdd
9 |
10 | TEST_FILE
11 | $PROJECT_DIR$/test/net-events.test.js
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/net_events_tap_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/net_events_test_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | project
4 |
5 | $PROJECT_DIR$/node_modules/mocha
6 | $PROJECT_DIR$
7 | true
8 | bdd
9 |
10 | TEST_FILE
11 | $PROJECT_DIR$/test/net-events.test.js
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/npm_test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/npm_test_mocha.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/promise_context_convention_spec_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | project
4 |
5 | $PROJECT_DIR$/node_modules/mocha
6 | $PROJECT_DIR$
7 | true
8 | bdd
9 |
10 | TEST_FILE
11 | $PROJECT_DIR$/test/promise-context-convention.spec.js
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/promises_tap_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
13 |
16 |
17 |
18 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/proper_exit_tap_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
10 |
13 |
14 |
15 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/run_tap_tests.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
10 |
13 |
14 |
15 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/test_async_context_test_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | project
4 |
5 | $PROJECT_DIR$/node_modules/mocha
6 | $PROJECT_DIR$
7 | true
8 | bdd
9 |
10 | TEST_FILE
11 | $PROJECT_DIR$/test/async-context.test.js
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/test_net_events_test_js.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | project
4 |
5 | $PROJECT_DIR$/node_modules/mocha
6 | $PROJECT_DIR$
7 | true
8 |
9 |
10 |
11 |
12 | bdd
13 |
14 | TEST_FILE
15 | $PROJECT_DIR$/test/net-events.test.js
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/with_http_server_and_client_request.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | project
4 |
5 | $PROJECT_DIR$/node_modules/mocha
6 | $PROJECT_DIR$
7 | true
8 | bdd
9 |
10 | SUITE
11 | $PROJECT_DIR$/test/http-events36-get.test.js
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | script:
2 | - "npm test"
3 |
4 | language: node_js
5 |
6 | node_js:
7 | - "6"
8 | - "8"
9 | - "10"
10 | - "12"
11 | - "13"
12 |
13 | sudo: false
14 | dist: trusty
15 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # `cls-hooked` Changelog
2 |
3 | ## v4.1.7
4 |
5 | * fix: npm engine semver to allow node 6.10.x.
6 | * chore: forked async-hook to updated its engine semver also
7 |
8 | ## v4.1.6
9 |
10 | * fix: Use the correct `err` variable name in try/catch. Thanks to [@enko](https://github.com/enko).
11 |
12 | ## v4.1.5
13 |
14 | * dep: update engine support ^4.7||^6.9.2||^7.3 to be same as `async-hook`'s
15 | * dep: update `async-hook` to 1.7.1
16 | * test: give `fs.watchFile` a little more time to pass on Travis CI
17 |
18 | ## v4.1.4
19 |
20 | * feat: supports node 4.5.0 now
21 | * test: add node 4 to travis
22 |
23 | ## v4.1.3
24 |
25 | * dep: updated dependencies. Fix eslint issues
26 | * feat: add runPromise
27 |
28 | ## v4.1.2
29 |
30 | * chore: republishing to npm v4.1.2
31 | * test: Update travis and strict npm engine to ^6.2.2
32 |
33 | ## v4.1.1
34 |
35 | * test: Updated travis and strict npm engine to ^6.2.2
36 |
37 | ## v4.1.0
38 |
39 | * feat: add `runAndReturn` method to get return value of `func` (from [@overlookmotel](https://github.com/overlookmotel/node-continuation-local-storage)).
40 |
41 |
42 | ## v4.0.1
43 |
44 | * feat: Same API but major change to implementation. Uses **unofficial** [AsyncWrap](https://github.com/nodejs/node-eps/blob/async-wrap-ep/XXX-asyncwrap-api.md) instead of [async-listener](https://github.com/othiym23/async-listener).
45 |
46 |
47 | ### v3.1.0 (2014-07-28):
48 |
49 | * Updated to use `async-listener@0.4.7` to pick up bug fixes.
50 |
51 | ### v3.0.0 (2013-12-14):
52 |
53 | * Removed the notion of a "default" or "global" context per namespace.
54 | It only existed to create a simpler interface for developing and testing the module,
55 | and created the potential for nasty information disclosure bugs
56 | (see [issue #14](https://github.com/othiym23/node-continuation-local-storage/issues/14)
57 | for details). This is potentially a breaking change, if you're depending on the global context,
58 | so semver says we have to bump the major version.
59 | * Added this changelog.
60 |
61 | ### v2.6.2 (2013-12-07):
62 |
63 | * `async-listener` and `emitter-listener` dependency refresh.
64 |
65 | ### v2.6.1 (2013-11-29):
66 |
67 | * `emitter-listener` has been extracted from `shimmer` into a standalone module
68 | for `namespace.bindEmitter()`.
69 |
70 | ### v2.6.0 (2013-11-27):
71 |
72 | * When an error is thrown in a CLS-bound continuation chain, attach the active
73 | context for the namespace to which the chain is bound. This is necessary
74 | because CLS and asyncListeners actually do too good a job of cleaning up
75 | after errors, and so they don't escape the continuation chain. New Relic
76 | needs the context so it can get the transaction active when the error
77 | happened for error tracing.
78 |
79 | ### v2.5.2 (2013-10-30):
80 |
81 | * `async-listener` dependency refresh for better support of node 0.8.0 - 0.8.3.
82 |
83 | ### v2.5.1 (2013-10-27):
84 |
85 | * `async-listener` dependency refresh.
86 |
87 | ### v2.5.0 (2013-10-27):
88 |
89 | * Relax the requirement that CLS contexts be pushed and popped from a stack,
90 | instead treating them as a set. This allows context interleaving (i.e.
91 | using the lower-level `namespace.enter()` and `namespace.exit()` API without
92 | any strict ordering dependencies). Everything works, but this still makes me
93 | a little uneasy.
94 | * EEs can now be bound to multiple namespaces, although this is likely to be
95 | slow.
96 |
97 | ### v2.4.4 (2013-10-27):
98 |
99 | * Even if you use an EE bound to a namespace outside a continuation chain, it
100 | shouldn't explode.
101 |
102 | ### v2.4.3 (2013-10-16):
103 |
104 | * `async-listener` dependency refresh.
105 |
106 | ### v2.4.2 (2013-10-13):
107 |
108 | * More tweaks for `async-listener` error handlers (just a dependency refresh).
109 |
110 | ### v2.4.1 (2013-10-12):
111 |
112 | * `async-listener` error listeners have gotten lots of tweaks. Update to newest
113 | API.
114 | * Only exit namespace context on error if a continuation chain is active.
115 |
116 | ### v2.4.0 (2013-10-11):
117 |
118 | * `async-listener` now supports error listeners. Update to newest API.
119 | * Namespace context should be exited on asynchronous errors.
120 |
121 | ### v2.3.4 (2013-10-03):
122 |
123 | * When EEs are in the middle of emitting, make sure that calls to
124 | `emitter.removeListener` are testing against non-monkeypatched versions of
125 | the event handlers (necessary so certain Connect middleware functions, such
126 | as `connect.limit`, run correctly).
127 |
128 | ### v2.3.3 (2013-10-02):
129 |
130 | * Ensure handler rebinding gets called even in case of errors.
131 | * Be consistent about making sure contexts are kept in a sane state when errors
132 | are thrown in EEs.
133 |
134 | ### v2.3.2 (2013-10-02):
135 |
136 | * Guard `on` / `addListener` remonkeypatching in `namespace.bindEmitter()` so
137 | that `shimmer` is only called to rebind if the monkeypatched versions have
138 | actually been replaced.
139 | * Don't try to call emit if there are no listeners on a bound EE.
140 | * Don't use `setImmediate` in tests, because it's not available in Node 0.8.x.
141 |
142 | ### v2.3.1 (2013-10-01):
143 |
144 | * Update to newest version of `async-listener`.
145 | * Fix typo.
146 |
147 | ### v2.3.0 (2013-09-30):
148 |
149 | * EventEmitters can now be bound to CLS namespaces. Because EEs act as coupling
150 | points between asynchronous domains, it's necessary for the EE binding to
151 | capture the CLS context both when the listener is added, and when a matching
152 | handler is firing because of a matching event being emitted.
153 |
154 | ### v2.2.1 (2013-09-30):
155 |
156 | * More tweaks to conform with `asyncListener` API changes.
157 | * Many more test cases to ensure `asyncListener` stuff is working with Node
158 | 0.8.x.
159 |
160 | ### v2.2.0 (2013-09-26):
161 |
162 | * Square up with latest `async-listener` / node PR #6011 changes.
163 |
164 | ### v2.1.2 (2013-09-09):
165 |
166 | * Document `namespace.createContext()`.
167 | * Fix issue where a value was *always* being returned from `namespace.run()`,
168 | even on error.
169 |
170 | ### v2.1.1 (2013-09-03):
171 |
172 | * Clean up minor typo in docs.
173 |
174 | ### v2.1.0 (2013-09-03):
175 |
176 | * Incorporate documentation from failed CLS PR.
177 | * `namespace.bind()` now also always exits the domain, even on error.
178 | * Namespaces can be destroyed.
179 | * `cls.reset()` allows tests to nuke all existing namespaces (use with care
180 | obviously).
181 |
182 | ### v2.0.0 (2013-09-01):
183 |
184 | * Use `async-listener` polyfill instead of `cls-glue`.
185 | * Incorporate tests from `cls-glue`.
186 |
187 | ### v1.1.1 (2013-09-01):
188 |
189 | * Namespace exits context even on error.
190 |
191 | ### v1.1.0 (2013-07-30):
192 |
193 | * Split createContext so it's part of the namespace API.
194 | * Tweak error message to be more informative.
195 |
196 | ### v1.0.1 (2013-07-25):
197 |
198 | * Correct Tim's email address.
199 |
200 | ### v1.0.0 (2013-07-25):
201 |
202 | * Each application of CLS is allocated its own "namespace", which bind data to
203 | continuation chains, either using `.run()` or `.bind()` to create a new
204 | nested context. These nested contexts are prototype chains that point back to
205 | a "default" / "global" context, with the default context for each namespace
206 | being a prototype-free "data bag" created with `Object.create(null)`.
207 |
208 | ### v0.1.1 (2013-05-03):
209 |
210 | * Document progress thus far.
211 |
212 | ### v0.1.0 (2013-05-03):
213 |
214 | * First attempt: basic API, docs, and tests.
215 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013-2016, Forrest L Norvell
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 | 2. Redistributions in binary form must reproduce the above copyright notice,
10 | this list of conditions and the following disclaimer in the documentation
11 | and/or other materials provided with the distribution.
12 |
13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://nodei.co/npm/cls-hooked/)
2 |
3 | [](https://travis-ci.org/Jeff-Lewis/cls-hooked)
4 |
5 | # Continuation-Local Storage ( Hooked )
6 |
7 | ### This is a fork of [CLS](https://github.com/othiym23/node-continuation-local-storage) using [AsyncWrap](https://github.com/nodejs/node-eps/blob/async-wrap-ep/XXX-asyncwrap-api.md) OR [async_hooks](https://github.com/nodejs/node/blob/master/doc/api/async_hooks.md) instead of [async-listener](https://github.com/othiym23/async-listener).
8 |
9 | ### When running Nodejs version < 8, this module uses [AsyncWrap](https://github.com/nodejs/node-eps/blob/async-wrap-ep/XXX-asyncwrap-api.md) which is an unsupported Nodejs API, so please consider the risk before using it.
10 |
11 | ### When running Nodejs version >= 8.2.1, this module uses the newer [async_hooks](https://github.com/nodejs/node/blob/master/doc/api/async_hooks.md) API which is considered `Experimental` by Nodejs.
12 |
13 | ### Thanks to [@trevnorris](https://github.com/trevnorris) for [AsyncWrap](https://github.com/nodejs/node-eps/blob/async-wrap-ep/XXX-asyncwrap-api.md), [async_hooks](https://github.com/nodejs/node/blob/master/doc/api/async_hooks.md) and all the async work in Node and [@AndreasMadsen](https://github.com/AndreasMadsen) for [async-hook](https://github.com/AndreasMadsen/async-hook)
14 |
15 | ### A little history of "AsyncWrap/async_hooks" and its incarnations
16 |
17 | 1. First implementation was called **[AsyncListener](https://github.com/nodejs/node-v0.x-archive/pull/6011)** in node v0.11 but was [removed from core](https://github.com/nodejs/node-v0.x-archive/pull/8110) prior to Nodejs v0.12
18 | 2. Second implementation called **[AsyncWrap, async-wrap or async_wrap](https://github.com/nodejs/node-eps/blob/async-wrap-ep/XXX-asyncwrap-api.md)** was included to Nodejs v0.12.
19 | - `AsyncWrap` is unofficial and undocumented but is currently in Nodejs versions 6 & 7
20 | - `cls-hooked` uses `AsyncWrap` when run in Node < 8.
21 | 3. Third implementation and [offically Node-eps accepted](https://github.com/nodejs/node-eps/blob/master/006-asynchooks-api.md) **AsyncHooks ([async_hooks](https://github.com/nodejs/node/blob/master/doc/api/async_hooks.md)) API** was included in Nodejs v8. :)
22 | **The latest version of `cls-hooked` uses [async_hooks](https://github.com/nodejs/node/blob/master/doc/api/async_hooks.md) API when run in Node >= 8.2.1**
23 |
24 | ---
25 | Continuation-local storage works like thread-local storage in threaded
26 | programming, but is based on chains of Node-style callbacks instead of threads.
27 | The standard Node convention of functions calling functions is very similar to
28 | something called ["continuation-passing style"][cps] in functional programming,
29 | and the name comes from the way this module allows you to set and get values
30 | that are scoped to the lifetime of these chains of function calls.
31 |
32 | Suppose you're writing a module that fetches a user and adds it to a session
33 | before calling a function passed in by a user to continue execution:
34 |
35 | ```javascript
36 | // setup.js
37 |
38 | var createNamespace = require('cls-hooked').createNamespace;
39 | var session = createNamespace('my session');
40 |
41 | var db = require('./lib/db.js');
42 |
43 | function start(options, next) {
44 | db.fetchUserById(options.id, function (error, user) {
45 | if (error) return next(error);
46 |
47 | session.set('user', user);
48 |
49 | next();
50 | });
51 | }
52 | ```
53 |
54 | Later on in the process of turning that user's data into an HTML page, you call
55 | another function (maybe defined in another module entirely) that wants to fetch
56 | the value you set earlier:
57 |
58 | ```javascript
59 | // send_response.js
60 |
61 | var getNamespace = require('cls-hooked').getNamespace;
62 | var session = getNamespace('my session');
63 |
64 | var render = require('./lib/render.js')
65 |
66 | function finish(response) {
67 | var user = session.get('user');
68 | render({user: user}).pipe(response);
69 | }
70 | ```
71 |
72 | When you set values in continuation-local storage, those values are accessible
73 | until all functions called from the original function – synchronously or
74 | asynchronously – have finished executing. This includes callbacks passed to
75 | `process.nextTick` and the [timer functions][] ([setImmediate][],
76 | [setTimeout][], and [setInterval][]), as well as callbacks passed to
77 | asynchronous functions that call native functions (such as those exported from
78 | the `fs`, `dns`, `zlib` and `crypto` modules).
79 |
80 | A simple rule of thumb is anywhere where you might have set a property on the
81 | `request` or `response` objects in an HTTP handler, you can (and should) now
82 | use continuation-local storage. This API is designed to allow you extend the
83 | scope of a variable across a sequence of function calls, but with values
84 | specific to each sequence of calls.
85 |
86 | Values are grouped into namespaces, created with `createNamespace()`. Sets of
87 | function calls are grouped together by calling them within the function passed
88 | to `.run()` on the namespace object. Calls to `.run()` can be nested, and each
89 | nested context this creates has its own copy of the set of values from the
90 | parent context. When a function is making multiple asynchronous calls, this
91 | allows each child call to get, set, and pass along its own context without
92 | overwriting the parent's.
93 |
94 | A simple, annotated example of how this nesting behaves:
95 |
96 | ```javascript
97 | var createNamespace = require('cls-hooked').createNamespace;
98 |
99 | var writer = createNamespace('writer');
100 | writer.run(function () {
101 | writer.set('value', 0);
102 |
103 | requestHandler();
104 | });
105 |
106 | function requestHandler() {
107 | writer.run(function(outer) {
108 | // writer.get('value') returns 0
109 | // outer.value is 0
110 | writer.set('value', 1);
111 | // writer.get('value') returns 1
112 | // outer.value is 1
113 | process.nextTick(function() {
114 | // writer.get('value') returns 1
115 | // outer.value is 1
116 | writer.run(function(inner) {
117 | // writer.get('value') returns 1
118 | // outer.value is 1
119 | // inner.value is 1
120 | writer.set('value', 2);
121 | // writer.get('value') returns 2
122 | // outer.value is 1
123 | // inner.value is 2
124 | });
125 | });
126 | });
127 |
128 | setTimeout(function() {
129 | // runs with the default context, because nested contexts have ended
130 | console.log(writer.get('value')); // prints 0
131 | }, 1000);
132 | }
133 | ```
134 |
135 | ## cls.createNamespace(name)
136 |
137 | * return: {Namespace}
138 |
139 | Each application wanting to use continuation-local values should create its own
140 | namespace. Reading from (or, more significantly, writing to) namespaces that
141 | don't belong to you is a faux pas.
142 |
143 | ## cls.getNamespace(name)
144 |
145 | * return: {Namespace}
146 |
147 | Look up an existing namespace.
148 |
149 | ## cls.destroyNamespace(name)
150 |
151 | Dispose of an existing namespace. WARNING: be sure to dispose of any references
152 | to destroyed namespaces in your old code, as contexts associated with them will
153 | no longer be propagated.
154 |
155 | ## cls.reset()
156 |
157 | Completely reset all continuation-local storage namespaces. WARNING: while this
158 | will stop the propagation of values in any existing namespaces, if there are
159 | remaining references to those namespaces in code, the associated storage will
160 | still be reachable, even though the associated state is no longer being updated.
161 | Make sure you clean up any references to destroyed namespaces yourself.
162 |
163 | ## process.namespaces
164 |
165 | * return: dictionary of {Namespace} objects
166 |
167 | Continuation-local storage has a performance cost, and so it isn't enabled
168 | until the module is loaded for the first time. Once the module is loaded, the
169 | current set of namespaces is available in `process.namespaces`, so library code
170 | that wants to use continuation-local storage only when it's active should test
171 | for the existence of `process.namespaces`.
172 |
173 | ## Class: Namespace
174 |
175 | Application-specific namespaces group values local to the set of functions
176 | whose calls originate from a callback passed to `namespace.run()` or
177 | `namespace.bind()`.
178 |
179 | ### namespace.active
180 |
181 | * return: the currently active context on a namespace
182 |
183 | ### namespace.set(key, value)
184 |
185 | * return: `value`
186 |
187 | Set a value on the current continuation context. Must be set within an active
188 | continuation chain started with `namespace.run()` or `namespace.bind()`.
189 |
190 | ### namespace.get(key)
191 |
192 | * return: the requested value, or `undefined`
193 |
194 | Look up a value on the current continuation context. Recursively searches from
195 | the innermost to outermost nested continuation context for a value associated
196 | with a given key. Must be set within an active continuation chain started with
197 | `namespace.run()` or `namespace.bind()`.
198 |
199 | ### namespace.run(callback)
200 |
201 | * return: the context associated with that callback
202 |
203 | Create a new context on which values can be set or read. Run all the functions
204 | that are called (either directly, or indirectly through asynchronous functions
205 | that take callbacks themselves) from the provided callback within the scope of
206 | that namespace. The new context is passed as an argument to the callback
207 | when it's called.
208 |
209 | ### namespace.runAndReturn(callback)
210 |
211 | * return: the return value of the callback
212 |
213 | Create a new context on which values can be set or read. Run all the functions
214 | that are called (either directly, or indirectly through asynchronous functions
215 | that take callbacks themselves) from the provided callback within the scope of
216 | that namespace. The new context is passed as an argument to the callback
217 | when it's called.
218 |
219 | Same as `namespace.run()` but returns the return value of the callback rather
220 | than the context.
221 |
222 | ### namespace.bind(callback, [context])
223 |
224 | * return: a callback wrapped up in a context closure
225 |
226 | Bind a function to the specified namespace. Works analogously to
227 | `Function.bind()` or `domain.bind()`. If context is omitted, it will default to
228 | the currently active context in the namespace, or create a new context if none
229 | is currently defined.
230 |
231 | ### namespace.bindEmitter(emitter)
232 |
233 | Bind an EventEmitter to a namespace. Operates similarly to `domain.add`, with a
234 | less generic name and the additional caveat that unlike domains, namespaces
235 | never implicitly bind EventEmitters to themselves when they're created within
236 | the context of an active namespace.
237 |
238 | The most likely time you'd want to use this is when you're using Express or
239 | Connect and want to make sure your middleware execution plays nice with CLS, or
240 | are doing other things with HTTP listeners:
241 |
242 | ```javascript
243 | http.createServer(function (req, res) {
244 | writer.bindEmitter(req);
245 | writer.bindEmitter(res);
246 |
247 | // do other stuff, some of which is asynchronous
248 | });
249 | ```
250 |
251 | ### namespace.createContext()
252 |
253 | * return: a context cloned from the currently active context
254 |
255 | Use this with `namespace.bind()`, if you want to have a fresh context at invocation time,
256 | as opposed to binding time:
257 |
258 | ```javascript
259 | function doSomething(p) {
260 | console.log("%s = %s", p, ns.get(p));
261 | }
262 |
263 | function bindLater(callback) {
264 | return writer.bind(callback, writer.createContext());
265 | }
266 |
267 | setInterval(function () {
268 | var bound = bindLater(doSomething);
269 | bound('test');
270 | }, 100);
271 | ```
272 |
273 | ## context
274 |
275 | A context is a plain object created using the enclosing context as its prototype.
276 |
277 | # copyright & license
278 |
279 | See [LICENSE](https://github.com/jeff-lewis/cls-hooked/blob/master/LICENSE)
280 | for the details of the BSD 2-clause "simplified" license used by
281 | `continuation-local-storage`. This package was developed in 2012-2013 (and is
282 | maintained now) by Forrest L Norvell, [@othiym23](https://github.com/othiym23),
283 | with considerable help from Timothy Caswell,
284 | [@creationix](https://github.com/creationix), working for The Node Firm. This
285 | work was underwritten by New Relic for use in their Node.js instrumentation
286 | agent, so maybe give that a look if you have some Node.js
287 | performance-monitoring needs.
288 |
289 | [timer functions]: https://nodejs.org/api/timers.html
290 | [setImmediate]: https://nodejs.org/api/timers.html#timers_setimmediate_callback_arg
291 | [setTimeout]: https://nodejs.org/api/timers.html#timers_settimeout_callback_delay_arg
292 | [setInterval]: https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_arg
293 | [cps]: http://en.wikipedia.org/wiki/Continuation-passing_style
294 |
--------------------------------------------------------------------------------
/context-legacy.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('util');
4 | const assert = require('assert');
5 | const wrapEmitter = require('emitter-listener');
6 | const asyncHook = require('async-hook-jl');
7 |
8 | const CONTEXTS_SYMBOL = 'cls@contexts';
9 | const ERROR_SYMBOL = 'error@context';
10 |
11 | //const trace = [];
12 |
13 | const invertedProviders = [];
14 | for (let key in asyncHook.providers) {
15 | invertedProviders[asyncHook.providers[key]] = key;
16 | }
17 |
18 | const DEBUG_CLS_HOOKED = process.env.DEBUG_CLS_HOOKED;
19 |
20 | let currentUid = -1;
21 |
22 | module.exports = {
23 | getNamespace: getNamespace,
24 | createNamespace: createNamespace,
25 | destroyNamespace: destroyNamespace,
26 | reset: reset,
27 | //trace: trace,
28 | ERROR_SYMBOL: ERROR_SYMBOL
29 | };
30 |
31 | function Namespace(name) {
32 | this.name = name;
33 | // changed in 2.7: no default context
34 | this.active = null;
35 | this._set = [];
36 | this.id = null;
37 | this._contexts = new Map();
38 | }
39 |
40 | Namespace.prototype.set = function set(key, value) {
41 | if (!this.active) {
42 | throw new Error('No context available. ns.run() or ns.bind() must be called first.');
43 | }
44 |
45 | if (DEBUG_CLS_HOOKED) {
46 | debug2(' SETTING KEY:' + key + '=' + value + ' in ns:' + this.name + ' uid:' + currentUid + ' active:' +
47 | util.inspect(this.active, true));
48 | }
49 | this.active[key] = value;
50 | return value;
51 | };
52 |
53 | Namespace.prototype.get = function get(key) {
54 | if (!this.active) {
55 | if (DEBUG_CLS_HOOKED) {
56 | debug2(' GETTING KEY:' + key + '=undefined' + ' ' + this.name + ' uid:' + currentUid + ' active:' +
57 | util.inspect(this.active, true));
58 | }
59 | return undefined;
60 | }
61 | if (DEBUG_CLS_HOOKED) {
62 | debug2(' GETTING KEY:' + key + '=' + this.active[key] + ' ' + this.name + ' uid:' + currentUid + ' active:' +
63 | util.inspect(this.active, true));
64 | }
65 | return this.active[key];
66 | };
67 |
68 | Namespace.prototype.createContext = function createContext() {
69 | if (DEBUG_CLS_HOOKED) {
70 | debug2(' CREATING Context: ' + this.name + ' uid:' + currentUid + ' len:' + this._set.length + ' ' + ' active:' +
71 | util.inspect(this.active, true, 2, true));
72 | }
73 |
74 | let context = Object.create(this.active ? this.active : Object.prototype);
75 | context._ns_name = this.name;
76 | context.id = currentUid;
77 |
78 | if (DEBUG_CLS_HOOKED) {
79 | debug2(' CREATED Context: ' + this.name + ' uid:' + currentUid + ' len:' + this._set.length + ' ' + ' context:' +
80 | util.inspect(context, true, 2, true));
81 | }
82 |
83 | return context;
84 | };
85 |
86 | Namespace.prototype.run = function run(fn) {
87 | let context = this.createContext();
88 | this.enter(context);
89 | try {
90 | if (DEBUG_CLS_HOOKED) {
91 | debug2(' BEFORE RUN: ' + this.name + ' uid:' + currentUid + ' len:' + this._set.length + ' ' +
92 | util.inspect(context));
93 | }
94 | fn(context);
95 | return context;
96 | }
97 | catch (exception) {
98 | if (exception) {
99 | exception[ERROR_SYMBOL] = context;
100 | }
101 | throw exception;
102 | }
103 | finally {
104 | if (DEBUG_CLS_HOOKED) {
105 | debug2(' AFTER RUN: ' + this.name + ' uid:' + currentUid + ' len:' + this._set.length + ' ' +
106 | util.inspect(context));
107 | }
108 | this.exit(context);
109 | }
110 | };
111 |
112 | Namespace.prototype.runAndReturn = function runAndReturn(fn) {
113 | var value;
114 | this.run(function (context) {
115 | value = fn(context);
116 | });
117 | return value;
118 | };
119 |
120 | /**
121 | * Uses global Promise and assumes Promise is cls friendly or wrapped already.
122 | * @param {function} fn
123 | * @returns {*}
124 | */
125 | Namespace.prototype.runPromise = function runPromise(fn) {
126 | let context = this.createContext();
127 | this.enter(context);
128 |
129 | let promise = fn(context);
130 | if (!promise || !promise.then || !promise.catch) {
131 | throw new Error('fn must return a promise.');
132 | }
133 |
134 | if (DEBUG_CLS_HOOKED) {
135 | debug2(' BEFORE runPromise: ' + this.name + ' uid:' + currentUid + ' len:' + this._set.length + ' ' +
136 | util.inspect(context));
137 | }
138 |
139 | return promise
140 | .then(result => {
141 | if (DEBUG_CLS_HOOKED) {
142 | debug2(' AFTER runPromise: ' + this.name + ' uid:' + currentUid + ' len:' + this._set.length + ' ' +
143 | util.inspect(context));
144 | }
145 | this.exit(context);
146 | return result;
147 | })
148 | .catch(err => {
149 | err[ERROR_SYMBOL] = context;
150 | if (DEBUG_CLS_HOOKED) {
151 | debug2(' AFTER runPromise: ' + this.name + ' uid:' + currentUid + ' len:' + this._set.length + ' ' +
152 | util.inspect(context));
153 | }
154 | this.exit(context);
155 | throw err;
156 | });
157 | };
158 |
159 | Namespace.prototype.bind = function bindFactory(fn, context) {
160 | if (!context) {
161 | if (!this.active) {
162 | context = this.createContext();
163 | }
164 | else {
165 | context = this.active;
166 | }
167 | }
168 |
169 | let self = this;
170 | return function clsBind() {
171 | self.enter(context);
172 | try {
173 | return fn.apply(this, arguments);
174 | }
175 | catch (exception) {
176 | if (exception) {
177 | exception[ERROR_SYMBOL] = context;
178 | }
179 | throw exception;
180 | }
181 | finally {
182 | self.exit(context);
183 | }
184 | };
185 | };
186 |
187 | Namespace.prototype.enter = function enter(context) {
188 | assert.ok(context, 'context must be provided for entering');
189 | if (DEBUG_CLS_HOOKED) {
190 | debug2(' ENTER ' + this.name + ' uid:' + currentUid + ' len:' + this._set.length + ' context: ' +
191 | util.inspect(context));
192 | }
193 |
194 | this._set.push(this.active);
195 | this.active = context;
196 | };
197 |
198 | Namespace.prototype.exit = function exit(context) {
199 | assert.ok(context, 'context must be provided for exiting');
200 | if (DEBUG_CLS_HOOKED) {
201 | debug2(' EXIT ' + this.name + ' uid:' + currentUid + ' len:' + this._set.length + ' context: ' +
202 | util.inspect(context));
203 | }
204 |
205 | // Fast path for most exits that are at the top of the stack
206 | if (this.active === context) {
207 | assert.ok(this._set.length, 'can\'t remove top context');
208 | this.active = this._set.pop();
209 | return;
210 | }
211 |
212 | // Fast search in the stack using lastIndexOf
213 | let index = this._set.lastIndexOf(context);
214 |
215 | if (index < 0) {
216 | if (DEBUG_CLS_HOOKED) {
217 | debug2('??ERROR?? context exiting but not entered - ignoring: ' + util.inspect(context));
218 | }
219 | assert.ok(index >= 0, 'context not currently entered; can\'t exit. \n' + util.inspect(this) + '\n' +
220 | util.inspect(context));
221 | } else {
222 | assert.ok(index, 'can\'t remove top context');
223 | this._set.splice(index, 1);
224 | }
225 | };
226 |
227 | Namespace.prototype.bindEmitter = function bindEmitter(emitter) {
228 | assert.ok(emitter.on && emitter.addListener && emitter.emit, 'can only bind real EEs');
229 |
230 | let namespace = this;
231 | let thisSymbol = 'context@' + this.name;
232 |
233 | // Capture the context active at the time the emitter is bound.
234 | function attach(listener) {
235 | if (!listener) {
236 | return;
237 | }
238 | if (!listener[CONTEXTS_SYMBOL]) {
239 | listener[CONTEXTS_SYMBOL] = Object.create(null);
240 | }
241 |
242 | listener[CONTEXTS_SYMBOL][thisSymbol] = {
243 | namespace: namespace,
244 | context: namespace.active
245 | };
246 | }
247 |
248 | // At emit time, bind the listener within the correct context.
249 | function bind(unwrapped) {
250 | if (!(unwrapped && unwrapped[CONTEXTS_SYMBOL])) {
251 | return unwrapped;
252 | }
253 |
254 | let wrapped = unwrapped;
255 | let unwrappedContexts = unwrapped[CONTEXTS_SYMBOL];
256 | Object.keys(unwrappedContexts).forEach(function (name) {
257 | let thunk = unwrappedContexts[name];
258 | wrapped = thunk.namespace.bind(wrapped, thunk.context);
259 | });
260 | return wrapped;
261 | }
262 |
263 | wrapEmitter(emitter, attach, bind);
264 | };
265 |
266 | /**
267 | * If an error comes out of a namespace, it will have a context attached to it.
268 | * This function knows how to find it.
269 | *
270 | * @param {Error} exception Possibly annotated error.
271 | */
272 | Namespace.prototype.fromException = function fromException(exception) {
273 | return exception[ERROR_SYMBOL];
274 | };
275 |
276 | function getNamespace(name) {
277 | return process.namespaces[name];
278 | }
279 |
280 | function createNamespace(name) {
281 | assert.ok(name, 'namespace must be given a name.');
282 |
283 | if (DEBUG_CLS_HOOKED) {
284 | debug2('CREATING NAMESPACE ' + name);
285 | }
286 | let namespace = new Namespace(name);
287 | namespace.id = currentUid;
288 |
289 | asyncHook.addHooks({
290 | init(uid, handle, provider, parentUid, parentHandle) {
291 | //parentUid = parentUid || currentUid; // Suggested usage but appears to work better for tracing modules.
292 | currentUid = uid;
293 |
294 | //CHAIN Parent's Context onto child if none exists. This is needed to pass net-events.spec
295 | if (parentUid) {
296 | namespace._contexts.set(uid, namespace._contexts.get(parentUid));
297 | if (DEBUG_CLS_HOOKED) {
298 | debug2('PARENTID: ' + name + ' uid:' + uid + ' parent:' + parentUid + ' provider:' + provider);
299 | }
300 | } else {
301 | namespace._contexts.set(currentUid, namespace.active);
302 | }
303 |
304 | if (DEBUG_CLS_HOOKED) {
305 | debug2('INIT ' + name + ' uid:' + uid + ' parent:' + parentUid + ' provider:' + invertedProviders[provider]
306 | + ' active:' + util.inspect(namespace.active, true));
307 | }
308 |
309 | },
310 | pre(uid, handle) {
311 | currentUid = uid;
312 | let context = namespace._contexts.get(uid);
313 | if (context) {
314 | if (DEBUG_CLS_HOOKED) {
315 | debug2(' PRE ' + name + ' uid:' + uid + ' handle:' + getFunctionName(handle) + ' context:' +
316 | util.inspect(context));
317 | }
318 |
319 | namespace.enter(context);
320 | } else {
321 | if (DEBUG_CLS_HOOKED) {
322 | debug2(' PRE MISSING CONTEXT ' + name + ' uid:' + uid + ' handle:' + getFunctionName(handle));
323 | }
324 | }
325 | },
326 | post(uid, handle) {
327 | currentUid = uid;
328 | let context = namespace._contexts.get(uid);
329 | if (context) {
330 | if (DEBUG_CLS_HOOKED) {
331 | debug2(' POST ' + name + ' uid:' + uid + ' handle:' + getFunctionName(handle) + ' context:' +
332 | util.inspect(context));
333 | }
334 |
335 | namespace.exit(context);
336 | } else {
337 | if (DEBUG_CLS_HOOKED) {
338 | debug2(' POST MISSING CONTEXT ' + name + ' uid:' + uid + ' handle:' + getFunctionName(handle));
339 | }
340 | }
341 | },
342 | destroy(uid) {
343 | currentUid = uid;
344 |
345 | if (DEBUG_CLS_HOOKED) {
346 | debug2('DESTROY ' + name + ' uid:' + uid + ' context:' + util.inspect(namespace._contexts.get(currentUid))
347 | + ' active:' + util.inspect(namespace.active, true));
348 | }
349 |
350 | namespace._contexts.delete(uid);
351 | }
352 | });
353 |
354 | process.namespaces[name] = namespace;
355 | return namespace;
356 | }
357 |
358 | function destroyNamespace(name) {
359 | let namespace = getNamespace(name);
360 |
361 | assert.ok(namespace, 'can\'t delete nonexistent namespace! "' + name + '"');
362 | assert.ok(namespace.id, 'don\'t assign to process.namespaces directly! ' + util.inspect(namespace));
363 |
364 | process.namespaces[name] = null;
365 | }
366 |
367 | function reset() {
368 | // must unregister async listeners
369 | if (process.namespaces) {
370 | Object.keys(process.namespaces).forEach(function (name) {
371 | destroyNamespace(name);
372 | });
373 | }
374 | process.namespaces = Object.create(null);
375 | }
376 |
377 | process.namespaces = process.namespaces || {};
378 |
379 | if (asyncHook._state && !asyncHook._state.enabled) {
380 | asyncHook.enable();
381 | }
382 |
383 | function debug2(msg) {
384 | if (process.env.DEBUG) {
385 | process._rawDebug(msg);
386 | }
387 | }
388 |
389 |
390 | /*function debug(from, ns) {
391 | process._rawDebug('DEBUG: ' + util.inspect({
392 | from: from,
393 | currentUid: currentUid,
394 | context: ns ? ns._contexts.get(currentUid) : 'no ns'
395 | }, true, 2, true));
396 | }*/
397 |
398 |
399 | function getFunctionName(fn) {
400 | if (!fn) {
401 | return fn;
402 | }
403 | if (typeof fn === 'function') {
404 | if (fn.name) {
405 | return fn.name;
406 | }
407 | return (fn.toString().trim().match(/^function\s*([^\s(]+)/) || [])[1];
408 | } else if (fn.constructor && fn.constructor.name) {
409 | return fn.constructor.name;
410 | }
411 | }
412 |
413 |
414 | // Add back to callstack
415 | if (DEBUG_CLS_HOOKED) {
416 | var stackChain = require('stack-chain');
417 | for (var modifier in stackChain.filter._modifiers) {
418 | stackChain.filter.deattach(modifier);
419 | }
420 | }
421 |
--------------------------------------------------------------------------------
/context.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 | 'use strict';
3 |
4 | const util = require('util');
5 | const assert = require('assert');
6 | const wrapEmitter = require('emitter-listener');
7 | const async_hooks = require('async_hooks');
8 |
9 | const CONTEXTS_SYMBOL = 'cls@contexts';
10 | const ERROR_SYMBOL = 'error@context';
11 |
12 | const DEBUG_CLS_HOOKED = process.env.DEBUG_CLS_HOOKED;
13 |
14 | let currentUid = -1;
15 |
16 | module.exports = {
17 | getNamespace: getNamespace,
18 | createNamespace: createNamespace,
19 | destroyNamespace: destroyNamespace,
20 | reset: reset,
21 | ERROR_SYMBOL: ERROR_SYMBOL
22 | };
23 |
24 | function Namespace(name) {
25 | this.name = name;
26 | // changed in 2.7: no default context
27 | this.active = null;
28 | this._set = [];
29 | this.id = null;
30 | this._contexts = new Map();
31 | this._indent = 0;
32 | }
33 |
34 | Namespace.prototype.set = function set(key, value) {
35 | if (!this.active) {
36 | throw new Error('No context available. ns.run() or ns.bind() must be called first.');
37 | }
38 |
39 | this.active[key] = value;
40 |
41 | if (DEBUG_CLS_HOOKED) {
42 | const indentStr = ' '.repeat(this._indent < 0 ? 0 : this._indent);
43 | debug2(indentStr + 'CONTEXT-SET KEY:' + key + '=' + value + ' in ns:' + this.name + ' currentUid:' + currentUid + ' active:' + util.inspect(this.active, {showHidden:true, depth:2, colors:true}));
44 | }
45 |
46 | return value;
47 | };
48 |
49 | Namespace.prototype.get = function get(key) {
50 | if (!this.active) {
51 | if (DEBUG_CLS_HOOKED) {
52 | const asyncHooksCurrentId = async_hooks.currentId();
53 | const triggerId = async_hooks.triggerAsyncId();
54 | const indentStr = ' '.repeat(this._indent < 0 ? 0 : this._indent);
55 | //debug2(indentStr + 'CONTEXT-GETTING KEY NO ACTIVE NS:' + key + '=undefined' + ' (' + this.name + ') currentUid:' + currentUid + ' active:' + util.inspect(this.active, {showHidden:true, depth:2, colors:true}));
56 | debug2(`${indentStr}CONTEXT-GETTING KEY NO ACTIVE NS: (${this.name}) ${key}=undefined currentUid:${currentUid} asyncHooksCurrentId:${asyncHooksCurrentId} triggerId:${triggerId} len:${this._set.length}`);
57 | }
58 | return undefined;
59 | }
60 | if (DEBUG_CLS_HOOKED) {
61 | const asyncHooksCurrentId = async_hooks.executionAsyncId();
62 | const triggerId = async_hooks.triggerAsyncId();
63 | const indentStr = ' '.repeat(this._indent < 0 ? 0 : this._indent);
64 | debug2(indentStr + 'CONTEXT-GETTING KEY:' + key + '=' + this.active[key] + ' (' + this.name + ') currentUid:' + currentUid + ' active:' + util.inspect(this.active, {showHidden:true, depth:2, colors:true}));
65 | debug2(`${indentStr}CONTEXT-GETTING KEY: (${this.name}) ${key}=${this.active[key]} currentUid:${currentUid} asyncHooksCurrentId:${asyncHooksCurrentId} triggerId:${triggerId} len:${this._set.length} active:${util.inspect(this.active)}`);
66 | }
67 | return this.active[key];
68 | };
69 |
70 | Namespace.prototype.createContext = function createContext() {
71 | // Prototype inherit existing context if created a new child context within existing context.
72 | let context = Object.create(this.active ? this.active : Object.prototype);
73 | context._ns_name = this.name;
74 | context.id = currentUid;
75 |
76 | if (DEBUG_CLS_HOOKED) {
77 | const asyncHooksCurrentId = async_hooks.executionAsyncId();
78 | const triggerId = async_hooks.triggerAsyncId();
79 | const indentStr = ' '.repeat(this._indent < 0 ? 0 : this._indent);
80 | debug2(`${indentStr}CONTEXT-CREATED Context: (${this.name}) currentUid:${currentUid} asyncHooksCurrentId:${asyncHooksCurrentId} triggerId:${triggerId} len:${this._set.length} context:${util.inspect(context, {showHidden:true, depth:2, colors:true})}`);
81 | }
82 |
83 | return context;
84 | };
85 |
86 | Namespace.prototype.run = function run(fn) {
87 | let context = this.createContext();
88 | this.enter(context);
89 |
90 | try {
91 | if (DEBUG_CLS_HOOKED) {
92 | const triggerId = async_hooks.triggerAsyncId();
93 | const asyncHooksCurrentId = async_hooks.executionAsyncId();
94 | const indentStr = ' '.repeat(this._indent < 0 ? 0 : this._indent);
95 | debug2(`${indentStr}CONTEXT-RUN BEGIN: (${this.name}) currentUid:${currentUid} triggerId:${triggerId} asyncHooksCurrentId:${asyncHooksCurrentId} len:${this._set.length} context:${util.inspect(context)}`);
96 | }
97 | fn(context);
98 | return context;
99 | } catch (exception) {
100 | if (exception) {
101 | exception[ERROR_SYMBOL] = context;
102 | }
103 | throw exception;
104 | } finally {
105 | if (DEBUG_CLS_HOOKED) {
106 | const triggerId = async_hooks.triggerAsyncId();
107 | const asyncHooksCurrentId = async_hooks.executionAsyncId();
108 | const indentStr = ' '.repeat(this._indent < 0 ? 0 : this._indent);
109 | debug2(`${indentStr}CONTEXT-RUN END: (${this.name}) currentUid:${currentUid} triggerId:${triggerId} asyncHooksCurrentId:${asyncHooksCurrentId} len:${this._set.length} ${util.inspect(context)}`);
110 | }
111 | this.exit(context);
112 | }
113 | };
114 |
115 | Namespace.prototype.runAndReturn = function runAndReturn(fn) {
116 | let value;
117 | this.run(function (context) {
118 | value = fn(context);
119 | });
120 | return value;
121 | };
122 |
123 | /**
124 | * Uses global Promise and assumes Promise is cls friendly or wrapped already.
125 | * @param {function} fn
126 | * @returns {*}
127 | */
128 | Namespace.prototype.runPromise = function runPromise(fn) {
129 | let context = this.createContext();
130 | this.enter(context);
131 |
132 | let promise = fn(context);
133 | if (!promise || !promise.then || !promise.catch) {
134 | throw new Error('fn must return a promise.');
135 | }
136 |
137 | if (DEBUG_CLS_HOOKED) {
138 | debug2('CONTEXT-runPromise BEFORE: (' + this.name + ') currentUid:' + currentUid + ' len:' + this._set.length + ' ' + util.inspect(context));
139 | }
140 |
141 | return promise
142 | .then(result => {
143 | if (DEBUG_CLS_HOOKED) {
144 | debug2('CONTEXT-runPromise AFTER then: (' + this.name + ') currentUid:' + currentUid + ' len:' + this._set.length + ' ' + util.inspect(context));
145 | }
146 | this.exit(context);
147 | return result;
148 | })
149 | .catch(err => {
150 | err[ERROR_SYMBOL] = context;
151 | if (DEBUG_CLS_HOOKED) {
152 | debug2('CONTEXT-runPromise AFTER catch: (' + this.name + ') currentUid:' + currentUid + ' len:' + this._set.length + ' ' + util.inspect(context));
153 | }
154 | this.exit(context);
155 | throw err;
156 | });
157 | };
158 |
159 | Namespace.prototype.bind = function bindFactory(fn, context) {
160 | if (!context) {
161 | if (!this.active) {
162 | context = this.createContext();
163 | } else {
164 | context = this.active;
165 | }
166 | }
167 |
168 | let self = this;
169 | return function clsBind() {
170 | self.enter(context);
171 | try {
172 | return fn.apply(this, arguments);
173 | } catch (exception) {
174 | if (exception) {
175 | exception[ERROR_SYMBOL] = context;
176 | }
177 | throw exception;
178 | } finally {
179 | self.exit(context);
180 | }
181 | };
182 | };
183 |
184 | Namespace.prototype.enter = function enter(context) {
185 | assert.ok(context, 'context must be provided for entering');
186 | if (DEBUG_CLS_HOOKED) {
187 | const asyncHooksCurrentId = async_hooks.executionAsyncId();
188 | const triggerId = async_hooks.triggerAsyncId();
189 | const indentStr = ' '.repeat(this._indent < 0 ? 0 : this._indent);
190 | debug2(`${indentStr}CONTEXT-ENTER: (${this.name}) currentUid:${currentUid} triggerId:${triggerId} asyncHooksCurrentId:${asyncHooksCurrentId} len:${this._set.length} ${util.inspect(context)}`);
191 | }
192 |
193 | this._set.push(this.active);
194 | this.active = context;
195 | };
196 |
197 | Namespace.prototype.exit = function exit(context) {
198 | assert.ok(context, 'context must be provided for exiting');
199 | if (DEBUG_CLS_HOOKED) {
200 | const asyncHooksCurrentId = async_hooks.executionAsyncId();
201 | const triggerId = async_hooks.triggerAsyncId();
202 | const indentStr = ' '.repeat(this._indent < 0 ? 0 : this._indent);
203 | debug2(`${indentStr}CONTEXT-EXIT: (${this.name}) currentUid:${currentUid} triggerId:${triggerId} asyncHooksCurrentId:${asyncHooksCurrentId} len:${this._set.length} ${util.inspect(context)}`);
204 | }
205 |
206 | // Fast path for most exits that are at the top of the stack
207 | if (this.active === context) {
208 | assert.ok(this._set.length, 'can\'t remove top context');
209 | this.active = this._set.pop();
210 | return;
211 | }
212 |
213 | // Fast search in the stack using lastIndexOf
214 | let index = this._set.lastIndexOf(context);
215 |
216 | if (index < 0) {
217 | if (DEBUG_CLS_HOOKED) {
218 | debug2('??ERROR?? context exiting but not entered - ignoring: ' + util.inspect(context));
219 | }
220 | assert.ok(index >= 0, 'context not currently entered; can\'t exit. \n' + util.inspect(this) + '\n' + util.inspect(context));
221 | } else {
222 | assert.ok(index, 'can\'t remove top context');
223 | this._set.splice(index, 1);
224 | }
225 | };
226 |
227 | Namespace.prototype.bindEmitter = function bindEmitter(emitter) {
228 | assert.ok(emitter.on && emitter.addListener && emitter.emit, 'can only bind real EEs');
229 |
230 | let namespace = this;
231 | let thisSymbol = 'context@' + this.name;
232 |
233 | // Capture the context active at the time the emitter is bound.
234 | function attach(listener) {
235 | if (!listener) {
236 | return;
237 | }
238 | if (!listener[CONTEXTS_SYMBOL]) {
239 | listener[CONTEXTS_SYMBOL] = Object.create(null);
240 | }
241 |
242 | listener[CONTEXTS_SYMBOL][thisSymbol] = {
243 | namespace: namespace,
244 | context: namespace.active
245 | };
246 | }
247 |
248 | // At emit time, bind the listener within the correct context.
249 | function bind(unwrapped) {
250 | if (!(unwrapped && unwrapped[CONTEXTS_SYMBOL])) {
251 | return unwrapped;
252 | }
253 |
254 | let wrapped = unwrapped;
255 | let unwrappedContexts = unwrapped[CONTEXTS_SYMBOL];
256 | Object.keys(unwrappedContexts).forEach(function (name) {
257 | let thunk = unwrappedContexts[name];
258 | wrapped = thunk.namespace.bind(wrapped, thunk.context);
259 | });
260 | return wrapped;
261 | }
262 |
263 | wrapEmitter(emitter, attach, bind);
264 | };
265 |
266 | /**
267 | * If an error comes out of a namespace, it will have a context attached to it.
268 | * This function knows how to find it.
269 | *
270 | * @param {Error} exception Possibly annotated error.
271 | */
272 | Namespace.prototype.fromException = function fromException(exception) {
273 | return exception[ERROR_SYMBOL];
274 | };
275 |
276 | function getNamespace(name) {
277 | return process.namespaces[name];
278 | }
279 |
280 | function createNamespace(name) {
281 | assert.ok(name, 'namespace must be given a name.');
282 |
283 | if (DEBUG_CLS_HOOKED) {
284 | debug2(`NS-CREATING NAMESPACE (${name})`);
285 | }
286 | let namespace = new Namespace(name);
287 | namespace.id = currentUid;
288 |
289 | const hook = async_hooks.createHook({
290 | init(asyncId, type, triggerId, resource) {
291 | currentUid = async_hooks.executionAsyncId();
292 |
293 | //CHAIN Parent's Context onto child if none exists. This is needed to pass net-events.spec
294 | // let initContext = namespace.active;
295 | // if(!initContext && triggerId) {
296 | // let parentContext = namespace._contexts.get(triggerId);
297 | // if (parentContext) {
298 | // namespace.active = parentContext;
299 | // namespace._contexts.set(currentUid, parentContext);
300 | // if (DEBUG_CLS_HOOKED) {
301 | // const indentStr = ' '.repeat(namespace._indent < 0 ? 0 : namespace._indent);
302 | // debug2(`${indentStr}INIT [${type}] (${name}) WITH PARENT CONTEXT asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect(namespace.active, true)} resource:${resource}`);
303 | // }
304 | // } else if (DEBUG_CLS_HOOKED) {
305 | // const indentStr = ' '.repeat(namespace._indent < 0 ? 0 : namespace._indent);
306 | // debug2(`${indentStr}INIT [${type}] (${name}) MISSING CONTEXT asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect(namespace.active, true)} resource:${resource}`);
307 | // }
308 | // }else {
309 | // namespace._contexts.set(currentUid, namespace.active);
310 | // if (DEBUG_CLS_HOOKED) {
311 | // const indentStr = ' '.repeat(namespace._indent < 0 ? 0 : namespace._indent);
312 | // debug2(`${indentStr}INIT [${type}] (${name}) asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect(namespace.active, true)} resource:${resource}`);
313 | // }
314 | // }
315 | if(namespace.active) {
316 | namespace._contexts.set(asyncId, namespace.active);
317 |
318 | if (DEBUG_CLS_HOOKED) {
319 | const indentStr = ' '.repeat(namespace._indent < 0 ? 0 : namespace._indent);
320 | debug2(`${indentStr}INIT [${type}] (${name}) asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect(namespace.active, {showHidden:true, depth:2, colors:true})} resource:${resource}`);
321 | }
322 | }else if(currentUid === 0){
323 | // CurrentId will be 0 when triggered from C++. Promise events
324 | // https://github.com/nodejs/node/blob/master/doc/api/async_hooks.md#triggerid
325 | const triggerId = async_hooks.triggerAsyncId();
326 | const triggerIdContext = namespace._contexts.get(triggerId);
327 | if (triggerIdContext) {
328 | namespace._contexts.set(asyncId, triggerIdContext);
329 | if (DEBUG_CLS_HOOKED) {
330 | const indentStr = ' '.repeat(namespace._indent < 0 ? 0 : namespace._indent);
331 | debug2(`${indentStr}INIT USING CONTEXT FROM TRIGGERID [${type}] (${name}) asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect(namespace.active, { showHidden: true, depth: 2, colors: true })} resource:${resource}`);
332 | }
333 | } else if (DEBUG_CLS_HOOKED) {
334 | const indentStr = ' '.repeat(namespace._indent < 0 ? 0 : namespace._indent);
335 | debug2(`${indentStr}INIT MISSING CONTEXT [${type}] (${name}) asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect(namespace.active, { showHidden: true, depth: 2, colors: true })} resource:${resource}`);
336 | }
337 | }
338 |
339 |
340 | if(DEBUG_CLS_HOOKED && type === 'PROMISE'){
341 | debug2(util.inspect(resource, {showHidden: true}));
342 | const parentId = resource.parentId;
343 | const indentStr = ' '.repeat(namespace._indent < 0 ? 0 : namespace._indent);
344 | debug2(`${indentStr}INIT RESOURCE-PROMISE [${type}] (${name}) parentId:${parentId} asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect(namespace.active, {showHidden:true, depth:2, colors:true})} resource:${resource}`);
345 | }
346 |
347 | },
348 | before(asyncId) {
349 | currentUid = async_hooks.executionAsyncId();
350 | let context;
351 |
352 | /*
353 | if(currentUid === 0){
354 | // CurrentId will be 0 when triggered from C++. Promise events
355 | // https://github.com/nodejs/node/blob/master/doc/api/async_hooks.md#triggerid
356 | //const triggerId = async_hooks.triggerAsyncId();
357 | context = namespace._contexts.get(asyncId); // || namespace._contexts.get(triggerId);
358 | }else{
359 | context = namespace._contexts.get(currentUid);
360 | }
361 | */
362 |
363 | //HACK to work with promises until they are fixed in node > 8.1.1
364 | context = namespace._contexts.get(asyncId) || namespace._contexts.get(currentUid);
365 |
366 | if (context) {
367 | if (DEBUG_CLS_HOOKED) {
368 | const triggerId = async_hooks.triggerAsyncId();
369 | const indentStr = ' '.repeat(namespace._indent < 0 ? 0 : namespace._indent);
370 | debug2(`${indentStr}BEFORE (${name}) asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect(namespace.active, {showHidden:true, depth:2, colors:true})} context:${util.inspect(context)}`);
371 | namespace._indent += 2;
372 | }
373 |
374 | namespace.enter(context);
375 |
376 | } else if (DEBUG_CLS_HOOKED) {
377 | const triggerId = async_hooks.triggerAsyncId();
378 | const indentStr = ' '.repeat(namespace._indent < 0 ? 0 : namespace._indent);
379 | debug2(`${indentStr}BEFORE MISSING CONTEXT (${name}) asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect(namespace.active, {showHidden:true, depth:2, colors:true})} namespace._contexts:${util.inspect(namespace._contexts, {showHidden:true, depth:2, colors:true})}`);
380 | namespace._indent += 2;
381 | }
382 | },
383 | after(asyncId) {
384 | currentUid = async_hooks.executionAsyncId();
385 | let context; // = namespace._contexts.get(currentUid);
386 | /*
387 | if(currentUid === 0){
388 | // CurrentId will be 0 when triggered from C++. Promise events
389 | // https://github.com/nodejs/node/blob/master/doc/api/async_hooks.md#triggerid
390 | //const triggerId = async_hooks.triggerAsyncId();
391 | context = namespace._contexts.get(asyncId); // || namespace._contexts.get(triggerId);
392 | }else{
393 | context = namespace._contexts.get(currentUid);
394 | }
395 | */
396 | //HACK to work with promises until they are fixed in node > 8.1.1
397 | context = namespace._contexts.get(asyncId) || namespace._contexts.get(currentUid);
398 |
399 | if (context) {
400 | if (DEBUG_CLS_HOOKED) {
401 | const triggerId = async_hooks.triggerAsyncId();
402 | namespace._indent -= 2;
403 | const indentStr = ' '.repeat(namespace._indent < 0 ? 0 : namespace._indent);
404 | debug2(`${indentStr}AFTER (${name}) asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect(namespace.active, {showHidden:true, depth:2, colors:true})} context:${util.inspect(context)}`);
405 | }
406 |
407 | namespace.exit(context);
408 |
409 | } else if (DEBUG_CLS_HOOKED) {
410 | const triggerId = async_hooks.triggerAsyncId();
411 | namespace._indent -= 2;
412 | const indentStr = ' '.repeat(namespace._indent < 0 ? 0 : namespace._indent);
413 | debug2(`${indentStr}AFTER MISSING CONTEXT (${name}) asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect(namespace.active, {showHidden:true, depth:2, colors:true})} context:${util.inspect(context)}`);
414 | }
415 | },
416 | destroy(asyncId) {
417 | currentUid = async_hooks.executionAsyncId();
418 | if (DEBUG_CLS_HOOKED) {
419 | const triggerId = async_hooks.triggerAsyncId();
420 | const indentStr = ' '.repeat(namespace._indent < 0 ? 0 : namespace._indent);
421 | debug2(`${indentStr}DESTROY (${name}) currentUid:${currentUid} asyncId:${asyncId} triggerId:${triggerId} active:${util.inspect(namespace.active, {showHidden:true, depth:2, colors:true})} context:${util.inspect(namespace._contexts.get(currentUid))}`);
422 | }
423 |
424 | namespace._contexts.delete(asyncId);
425 | }
426 | });
427 |
428 | hook.enable();
429 |
430 | process.namespaces[name] = namespace;
431 | return namespace;
432 | }
433 |
434 | function destroyNamespace(name) {
435 | let namespace = getNamespace(name);
436 |
437 | assert.ok(namespace, 'can\'t delete nonexistent namespace! "' + name + '"');
438 | assert.ok(namespace.id, 'don\'t assign to process.namespaces directly! ' + util.inspect(namespace));
439 |
440 | process.namespaces[name] = null;
441 | }
442 |
443 | function reset() {
444 | // must unregister async listeners
445 | if (process.namespaces) {
446 | Object.keys(process.namespaces).forEach(function (name) {
447 | destroyNamespace(name);
448 | });
449 | }
450 | process.namespaces = Object.create(null);
451 | }
452 |
453 | process.namespaces = process.namespaces || {};
454 |
455 | //const fs = require('fs');
456 | function debug2(...args) {
457 | if (DEBUG_CLS_HOOKED) {
458 | //fs.writeSync(1, `${util.format(...args)}\n`);
459 | process._rawDebug(`${util.format(...args)}`);
460 | }
461 | }
462 |
463 | /*function getFunctionName(fn) {
464 | if (!fn) {
465 | return fn;
466 | }
467 | if (typeof fn === 'function') {
468 | if (fn.name) {
469 | return fn.name;
470 | }
471 | return (fn.toString().trim().match(/^function\s*([^\s(]+)/) || [])[1];
472 | } else if (fn.constructor && fn.constructor.name) {
473 | return fn.constructor.name;
474 | }
475 | }*/
476 |
477 |
478 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const semver = require('semver');
4 |
5 | /**
6 | * In order to increase node version support, this loads the version of context
7 | * that is appropriate for the version of on nodejs that is running.
8 | * Node < v8 - uses AsyncWrap and async-hooks-jl
9 | * Node >= v8 - uses native async-hooks
10 | */
11 | if(process && semver.gte(process.versions.node, '8.0.0')){
12 | module.exports = require('./context');
13 | }else{
14 | module.exports = require('./context-legacy');
15 | }
16 |
--------------------------------------------------------------------------------
/logs/async-hook-passing.log:
--------------------------------------------------------------------------------
1 | ./test/net-events.tap.js creating Context in ns:net active:null
2 | created Context in ns:net context:{ _ns_name: 'net' }
3 | ENTER net uid:-6 context: { _ns_name: 'net' }
4 | before run: { _ns_name: 'net' }
5 | setting key:test=originalValue in ns:net uid:-6 active:{ _ns_name: 'net' }
6 | creating Context in ns:net active:{ _ns_name: 'net', test: 'originalValue' }
7 | created Context in ns:net context:{ _ns_name: 'net' }
8 | ENTER net uid:-6 context: { _ns_name: 'net' }
9 | before run: { _ns_name: 'net' }
10 | setting key:test=newContextValue in ns:net uid:-6 active:{ _ns_name: 'net' }
11 | INIT net uid:22 parent:null provider:TCPWRAP active:{ _ns_name: 'net', test: 'newContextValue' }
12 | INIT net uid:-7 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
13 | after run: { _ns_name: 'net', test: 'newContextValue' }
14 | EXIT net uid:-7 context: { _ns_name: 'net', test: 'newContextValue' }
15 | after run: { _ns_name: 'net', test: 'originalValue' }
16 | EXIT net uid:-7 context: { _ns_name: 'net', test: 'originalValue' }
17 | PRE MISSING CONTEXT net uid:-1 handle:NextTickWrap
18 | POST MISSING CONTEXT net uid:-1 handle:NextTickWrap
19 | DESTROY net uid:-1 context:undefined active:null
20 | PRE MISSING CONTEXT net uid:-2 handle:NextTickWrap
21 | POST MISSING CONTEXT net uid:-2 handle:NextTickWrap
22 | DESTROY net uid:-2 context:undefined active:null
23 | PRE MISSING CONTEXT net uid:-3 handle:NextTickWrap
24 | POST MISSING CONTEXT net uid:-3 handle:NextTickWrap
25 | DESTROY net uid:-3 context:undefined active:null
26 | PRE MISSING CONTEXT net uid:-4 handle:NextTickWrap
27 | POST MISSING CONTEXT net uid:-4 handle:NextTickWrap
28 | DESTROY net uid:-4 context:undefined active:null
29 | PRE MISSING CONTEXT net uid:-5 handle:NextTickWrap
30 | POST MISSING CONTEXT net uid:-5 handle:NextTickWrap
31 | DESTROY net uid:-5 context:undefined active:null
32 | PRE MISSING CONTEXT net uid:-6 handle:NextTickWrap
33 | POST MISSING CONTEXT net uid:-6 handle:NextTickWrap
34 | DESTROY net uid:-6 context:undefined active:null
35 | PRE net uid:-7 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
36 | ENTER net uid:-7 context: { _ns_name: 'net', test: 'newContextValue' }
37 | creating Context in ns:net active:{ _ns_name: 'net', test: 'newContextValue' }
38 | created Context in ns:net context:{ _ns_name: 'net' }
39 | ENTER net uid:-7 context: { _ns_name: 'net' }
40 | before run: { _ns_name: 'net' }
41 | setting key:test=MONKEY in ns:net uid:-7 active:{ _ns_name: 'net' }
42 | INIT net uid:23 parent:null provider:TCPWRAP active:{ _ns_name: 'net', test: 'MONKEY' }
43 | INIT net uid:24 parent:null provider:GETADDRINFOREQWRAP active:{ _ns_name: 'net', test: 'MONKEY' }
44 | after run: { _ns_name: 'net', test: 'MONKEY' }
45 | EXIT net uid:24 context: { _ns_name: 'net', test: 'MONKEY' }
46 | POST net uid:-7 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
47 | EXIT net uid:-7 context: { _ns_name: 'net', test: 'newContextValue' }
48 | DESTROY net uid:-7 context:undefined active:null
49 | PRE net uid:24 entryPoint:GetAddrInfoReqWrap context:{ _ns_name: 'net', test: 'MONKEY' }
50 | ENTER net uid:24 context: { _ns_name: 'net', test: 'MONKEY' }
51 | INIT net uid:25 parent:null provider:TCPCONNECTWRAP active:{ _ns_name: 'net', test: 'MONKEY' }
52 | POST net uid:24 handle:GetAddrInfoReqWrap context:{ _ns_name: 'net', test: 'MONKEY' }
53 | EXIT net uid:24 context: { _ns_name: 'net', test: 'MONKEY' }
54 | DESTROY net uid:24 context:undefined active:null
55 | INIT net uid:26 parent:22 provider:TCPWRAP active:null
56 | PARENTID: net uid:26 parent:22 provider:15
57 | PRE net uid:22 entryPoint:TCP context:{ _ns_name: 'net', test: 'newContextValue' }
58 | ENTER net uid:22 context: { _ns_name: 'net', test: 'newContextValue' }
59 | getting key:test=newContextValue in ns:net uid:22 active:{ _ns_name: 'net', test: 'newContextValue' }
60 | INIT net uid:-8 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
61 | INIT net uid:-9 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
62 | INIT net uid:-10 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
63 | INIT net uid:-11 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
64 | POST net uid:22 handle:TCP context:{ _ns_name: 'net', test: 'newContextValue' }
65 | EXIT net uid:22 context: { _ns_name: 'net', test: 'newContextValue' }
66 | PRE net uid:-8 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
67 | ENTER net uid:-8 context: { _ns_name: 'net', test: 'newContextValue' }
68 | POST net uid:-8 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
69 | EXIT net uid:-8 context: { _ns_name: 'net', test: 'newContextValue' }
70 | DESTROY net uid:-8 context:undefined active:null
71 | PRE net uid:-9 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
72 | ENTER net uid:-9 context: { _ns_name: 'net', test: 'newContextValue' }
73 | POST net uid:-9 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
74 | EXIT net uid:-9 context: { _ns_name: 'net', test: 'newContextValue' }
75 | DESTROY net uid:-9 context:undefined active:null
76 | PRE net uid:-10 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
77 | ENTER net uid:-10 context: { _ns_name: 'net', test: 'newContextValue' }
78 | POST net uid:-10 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
79 | EXIT net uid:-10 context: { _ns_name: 'net', test: 'newContextValue' }
80 | DESTROY net uid:-10 context:undefined active:null
81 | PRE net uid:-11 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
82 | ENTER net uid:-11 context: { _ns_name: 'net', test: 'newContextValue' }
83 | POST net uid:-11 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
84 | EXIT net uid:-11 context: { _ns_name: 'net', test: 'newContextValue' }
85 | DESTROY net uid:-11 context:undefined active:null
86 | PRE net uid:25 entryPoint:TCPConnectWrap context:{ _ns_name: 'net', test: 'MONKEY' }
87 | ENTER net uid:25 context: { _ns_name: 'net', test: 'MONKEY' }
88 | getting key:test=MONKEY in ns:net uid:25 active:{ _ns_name: 'net', test: 'MONKEY' }
89 | INIT net uid:-12 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
90 | .INIT net uid:-13 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
91 | INIT net uid:-14 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
92 | INIT net uid:-15 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
93 | INIT net uid:-16 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
94 | POST net uid:25 handle:TCPConnectWrap context:{ _ns_name: 'net', test: 'MONKEY' }
95 | EXIT net uid:25 context: { _ns_name: 'net', test: 'MONKEY' }
96 | PRE net uid:-12 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
97 | ENTER net uid:-12 context: { _ns_name: 'net', test: 'MONKEY' }
98 | POST net uid:-12 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
99 | EXIT net uid:-12 context: { _ns_name: 'net', test: 'MONKEY' }
100 | DESTROY net uid:-12 context:undefined active:null
101 | PRE net uid:-13 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
102 | ENTER net uid:-13 context: { _ns_name: 'net', test: 'MONKEY' }
103 | POST net uid:-13 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
104 | EXIT net uid:-13 context: { _ns_name: 'net', test: 'MONKEY' }
105 | DESTROY net uid:-13 context:undefined active:null
106 | PRE net uid:-14 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
107 | ENTER net uid:-14 context: { _ns_name: 'net', test: 'MONKEY' }
108 | POST net uid:-14 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
109 | EXIT net uid:-14 context: { _ns_name: 'net', test: 'MONKEY' }
110 | DESTROY net uid:-14 context:undefined active:null
111 | PRE net uid:-15 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
112 | ENTER net uid:-15 context: { _ns_name: 'net', test: 'MONKEY' }
113 | POST net uid:-15 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
114 | EXIT net uid:-15 context: { _ns_name: 'net', test: 'MONKEY' }
115 | DESTROY net uid:-15 context:undefined active:null
116 | PRE net uid:-16 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
117 | ENTER net uid:-16 context: { _ns_name: 'net', test: 'MONKEY' }
118 | POST net uid:-16 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
119 | EXIT net uid:-16 context: { _ns_name: 'net', test: 'MONKEY' }
120 | DESTROY net uid:-16 context:undefined active:null
121 | DESTROY net uid:25 context:undefined active:null
122 | PRE net uid:26 entryPoint:TCP context:{ _ns_name: 'net', test: 'newContextValue' }
123 | ENTER net uid:26 context: { _ns_name: 'net', test: 'newContextValue' }
124 | getting key:test=newContextValue in ns:net uid:26 active:{ _ns_name: 'net', test: 'newContextValue' }
125 | INIT net uid:-17 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
126 | .INIT net uid:-18 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
127 | INIT net uid:-19 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
128 | INIT net uid:-20 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
129 | INIT net uid:-21 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
130 | POST net uid:26 handle:TCP context:{ _ns_name: 'net', test: 'newContextValue' }
131 | EXIT net uid:26 context: { _ns_name: 'net', test: 'newContextValue' }
132 | PRE net uid:-17 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
133 | ENTER net uid:-17 context: { _ns_name: 'net', test: 'newContextValue' }
134 | POST net uid:-17 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
135 | EXIT net uid:-17 context: { _ns_name: 'net', test: 'newContextValue' }
136 | DESTROY net uid:-17 context:undefined active:null
137 | PRE net uid:-18 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
138 | ENTER net uid:-18 context: { _ns_name: 'net', test: 'newContextValue' }
139 | POST net uid:-18 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
140 | EXIT net uid:-18 context: { _ns_name: 'net', test: 'newContextValue' }
141 | DESTROY net uid:-18 context:undefined active:null
142 | PRE net uid:-19 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
143 | ENTER net uid:-19 context: { _ns_name: 'net', test: 'newContextValue' }
144 | POST net uid:-19 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
145 | EXIT net uid:-19 context: { _ns_name: 'net', test: 'newContextValue' }
146 | DESTROY net uid:-19 context:undefined active:null
147 | PRE net uid:-20 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
148 | ENTER net uid:-20 context: { _ns_name: 'net', test: 'newContextValue' }
149 | INIT net uid:27 parent:null provider:SHUTDOWNWRAP active:{ _ns_name: 'net', test: 'newContextValue' }
150 | POST net uid:-20 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
151 | EXIT net uid:-20 context: { _ns_name: 'net', test: 'newContextValue' }
152 | DESTROY net uid:-20 context:undefined active:null
153 | PRE net uid:-21 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
154 | ENTER net uid:-21 context: { _ns_name: 'net', test: 'newContextValue' }
155 | POST net uid:-21 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
156 | EXIT net uid:-21 context: { _ns_name: 'net', test: 'newContextValue' }
157 | DESTROY net uid:-21 context:undefined active:null
158 | DESTROY net uid:22 context:undefined active:null
159 | PRE net uid:27 entryPoint:ShutdownWrap context:{ _ns_name: 'net', test: 'newContextValue' }
160 | ENTER net uid:27 context: { _ns_name: 'net', test: 'newContextValue' }
161 | POST net uid:27 handle:ShutdownWrap context:{ _ns_name: 'net', test: 'newContextValue' }
162 | EXIT net uid:27 context: { _ns_name: 'net', test: 'newContextValue' }
163 | DESTROY net uid:27 context:undefined active:null
164 | PRE net uid:23 entryPoint:TCP context:{ _ns_name: 'net', test: 'MONKEY' }
165 | ENTER net uid:23 context: { _ns_name: 'net', test: 'MONKEY' }
166 | getting key:test=MONKEY in ns:net uid:23 active:{ _ns_name: 'net', test: 'MONKEY' }
167 | INIT net uid:-22 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
168 | .INIT net uid:-23 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
169 | INIT net uid:-24 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
170 | INIT net uid:-25 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
171 | .INIT net uid:-26 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
172 | INIT net uid:-27 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
173 | INIT net uid:-28 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
174 | POST net uid:23 handle:TCP context:{ _ns_name: 'net', test: 'MONKEY' }
175 | EXIT net uid:23 context: { _ns_name: 'net', test: 'MONKEY' }
176 | PRE net uid:-22 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
177 | ENTER net uid:-22 context: { _ns_name: 'net', test: 'MONKEY' }
178 | POST net uid:-22 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
179 | EXIT net uid:-22 context: { _ns_name: 'net', test: 'MONKEY' }
180 | DESTROY net uid:-22 context:undefined active:null
181 | PRE net uid:-23 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
182 | ENTER net uid:-23 context: { _ns_name: 'net', test: 'MONKEY' }
183 | POST net uid:-23 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
184 | EXIT net uid:-23 context: { _ns_name: 'net', test: 'MONKEY' }
185 | DESTROY net uid:-23 context:undefined active:null
186 | PRE net uid:-24 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
187 | ENTER net uid:-24 context: { _ns_name: 'net', test: 'MONKEY' }
188 | POST net uid:-24 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
189 | EXIT net uid:-24 context: { _ns_name: 'net', test: 'MONKEY' }
190 | DESTROY net uid:-24 context:undefined active:null
191 | PRE net uid:-25 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
192 | ENTER net uid:-25 context: { _ns_name: 'net', test: 'MONKEY' }
193 | POST net uid:-25 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
194 | EXIT net uid:-25 context: { _ns_name: 'net', test: 'MONKEY' }
195 | DESTROY net uid:-25 context:undefined active:null
196 | PRE net uid:-26 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
197 | ENTER net uid:-26 context: { _ns_name: 'net', test: 'MONKEY' }
198 | POST net uid:-26 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
199 | EXIT net uid:-26 context: { _ns_name: 'net', test: 'MONKEY' }
200 | DESTROY net uid:-26 context:undefined active:null
201 | PRE net uid:-27 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
202 | ENTER net uid:-27 context: { _ns_name: 'net', test: 'MONKEY' }
203 | POST net uid:-27 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
204 | EXIT net uid:-27 context: { _ns_name: 'net', test: 'MONKEY' }
205 | DESTROY net uid:-27 context:undefined active:null
206 | PRE net uid:-28 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
207 | ENTER net uid:-28 context: { _ns_name: 'net', test: 'MONKEY' }
208 | POST net uid:-28 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
209 | EXIT net uid:-28 context: { _ns_name: 'net', test: 'MONKEY' }
210 | DESTROY net uid:-28 context:undefined active:null
211 | PRE net uid:23 entryPoint:TCP context:{ _ns_name: 'net', test: 'MONKEY' }
212 | ENTER net uid:23 context: { _ns_name: 'net', test: 'MONKEY' }
213 | INIT net uid:-29 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
214 | INIT net uid:-30 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
215 | POST net uid:23 handle:TCP context:{ _ns_name: 'net', test: 'MONKEY' }
216 | EXIT net uid:23 context: { _ns_name: 'net', test: 'MONKEY' }
217 | PRE net uid:-29 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
218 | ENTER net uid:-29 context: { _ns_name: 'net', test: 'MONKEY' }
219 | POST net uid:-29 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
220 | EXIT net uid:-29 context: { _ns_name: 'net', test: 'MONKEY' }
221 | DESTROY net uid:-29 context:undefined active:null
222 | PRE net uid:-30 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
223 | ENTER net uid:-30 context: { _ns_name: 'net', test: 'MONKEY' }
224 | POST net uid:-30 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
225 | EXIT net uid:-30 context: { _ns_name: 'net', test: 'MONKEY' }
226 | DESTROY net uid:-30 context:undefined active:null
227 | PRE net uid:23 entryPoint:TCP context:{ _ns_name: 'net', test: 'MONKEY' }
228 | ENTER net uid:23 context: { _ns_name: 'net', test: 'MONKEY' }
229 | POST net uid:23 handle:TCP context:{ _ns_name: 'net', test: 'MONKEY' }
230 | EXIT net uid:23 context: { _ns_name: 'net', test: 'MONKEY' }
231 | DESTROY net uid:23 context:undefined active:null
232 | PRE net uid:26 entryPoint:TCP context:{ _ns_name: 'net', test: 'newContextValue' }
233 | ENTER net uid:26 context: { _ns_name: 'net', test: 'newContextValue' }
234 | INIT net uid:-31 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
235 | INIT net uid:-32 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
236 | INIT net uid:-33 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
237 | POST net uid:26 handle:TCP context:{ _ns_name: 'net', test: 'newContextValue' }
238 | EXIT net uid:26 context: { _ns_name: 'net', test: 'newContextValue' }
239 | PRE net uid:-31 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
240 | ENTER net uid:-31 context: { _ns_name: 'net', test: 'newContextValue' }
241 | POST net uid:-31 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
242 | EXIT net uid:-31 context: { _ns_name: 'net', test: 'newContextValue' }
243 | DESTROY net uid:-31 context:undefined active:null
244 | PRE net uid:-32 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
245 | ENTER net uid:-32 context: { _ns_name: 'net', test: 'newContextValue' }
246 | POST net uid:-32 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
247 | EXIT net uid:-32 context: { _ns_name: 'net', test: 'newContextValue' }
248 | DESTROY net uid:-32 context:undefined active:null
249 | PRE net uid:-33 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
250 | ENTER net uid:-33 context: { _ns_name: 'net', test: 'newContextValue' }
251 | POST net uid:-33 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
252 | EXIT net uid:-33 context: { _ns_name: 'net', test: 'newContextValue' }
253 | DESTROY net uid:-33 context:undefined active:null
254 | PRE net uid:26 entryPoint:TCP context:{ _ns_name: 'net', test: 'newContextValue' }
255 | ENTER net uid:26 context: { _ns_name: 'net', test: 'newContextValue' }
256 | POST net uid:26 handle:TCP context:{ _ns_name: 'net', test: 'newContextValue' }
257 | EXIT net uid:26 context: { _ns_name: 'net', test: 'newContextValue' }
258 | DESTROY net uid:26 context:undefined active:null
259 | INIT net uid:-34 parent:null provider:NONE active:null
260 | INIT net uid:-35 parent:null provider:NONE active:null
261 | INIT net uid:-36 parent:null provider:NONE active:null
262 |
--------------------------------------------------------------------------------
/logs/async-hook.log:
--------------------------------------------------------------------------------
1 | ./test/net-events.tap.js creating Context in ns:net active:null
2 | created Context in ns:net context:{ _ns_name: 'net' }
3 | ENTER net uid:-1 context: { _ns_name: 'net' }
4 | before run: { _ns_name: 'net' }
5 | setting key:test=originalValue in ns:net uid:-1 active:{ _ns_name: 'net' }
6 | creating Context in ns:net active:{ _ns_name: 'net', test: 'originalValue' }
7 | created Context in ns:net context:{ _ns_name: 'net' }
8 | ENTER net uid:-1 context: { _ns_name: 'net' }
9 | before run: { _ns_name: 'net' }
10 | setting key:test=newContextValue in ns:net uid:-1 active:{ _ns_name: 'net' }
11 | INIT net uid:22 parent:null provider:TCPWRAP active:{ _ns_name: 'net', test: 'newContextValue' }
12 | INIT net uid:-7 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
13 | after run: { _ns_name: 'net', test: 'newContextValue' }
14 | EXIT net uid:-7 context: { _ns_name: 'net', test: 'newContextValue' }
15 | after run: { _ns_name: 'net', test: 'originalValue' }
16 | EXIT net uid:-7 context: { _ns_name: 'net', test: 'originalValue' }
17 | PRE MISSING CONTEXT net uid:-1 handle:NextTickWrap
18 | POST MISSING CONTEXT net uid:-1 handle:NextTickWrap
19 | DESTROY net uid:-1 context:undefined active:null
20 | PRE MISSING CONTEXT net uid:-2 handle:NextTickWrap
21 | POST MISSING CONTEXT net uid:-2 handle:NextTickWrap
22 | DESTROY net uid:-2 context:undefined active:null
23 | PRE MISSING CONTEXT net uid:-3 handle:NextTickWrap
24 | POST MISSING CONTEXT net uid:-3 handle:NextTickWrap
25 | DESTROY net uid:-3 context:undefined active:null
26 | PRE MISSING CONTEXT net uid:-4 handle:NextTickWrap
27 | POST MISSING CONTEXT net uid:-4 handle:NextTickWrap
28 | DESTROY net uid:-4 context:undefined active:null
29 | PRE MISSING CONTEXT net uid:-5 handle:NextTickWrap
30 | POST MISSING CONTEXT net uid:-5 handle:NextTickWrap
31 | DESTROY net uid:-5 context:undefined active:null
32 | PRE MISSING CONTEXT net uid:-6 handle:NextTickWrap
33 | POST MISSING CONTEXT net uid:-6 handle:NextTickWrap
34 | DESTROY net uid:-6 context:undefined active:null
35 | ENTER net uid:-7 context: { _ns_name: 'net', test: 'newContextValue' }
36 | PRE net uid:-7 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
37 | creating Context in ns:net active:{ _ns_name: 'net', test: 'newContextValue' }
38 | created Context in ns:net context:{ _ns_name: 'net' }
39 | ENTER net uid:-7 context: { _ns_name: 'net' }
40 | before run: { _ns_name: 'net' }
41 | setting key:test=MONKEY in ns:net uid:-7 active:{ _ns_name: 'net' }
42 | INIT net uid:23 parent:null provider:TCPWRAP active:{ _ns_name: 'net', test: 'MONKEY' }
43 | INIT net uid:24 parent:null provider:GETADDRINFOREQWRAP active:{ _ns_name: 'net', test: 'MONKEY' }
44 | after run: { _ns_name: 'net', test: 'MONKEY' }
45 | EXIT net uid:24 context: { _ns_name: 'net', test: 'MONKEY' }
46 | EXIT net uid:-7 context: { _ns_name: 'net', test: 'newContextValue' }
47 | POST net uid:-7 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
48 | DESTROY net uid:-7 context:undefined active:null
49 | ENTER net uid:24 context: { _ns_name: 'net', test: 'MONKEY' }
50 | PRE net uid:24 entryPoint:GetAddrInfoReqWrap context:{ _ns_name: 'net', test: 'MONKEY' }
51 | INIT net uid:25 parent:null provider:TCPCONNECTWRAP active:{ _ns_name: 'net', test: 'MONKEY' }
52 | EXIT net uid:24 context: { _ns_name: 'net', test: 'MONKEY' }
53 | POST net uid:24 handle:GetAddrInfoReqWrap context:{ _ns_name: 'net', test: 'MONKEY' }
54 | DESTROY net uid:24 context:undefined active:null
55 | INIT net uid:26 parent:22 provider:TCPWRAP active:null
56 | PARENTID: net uid:26 parent:22 provider:15
57 | ENTER net uid:22 context: { _ns_name: 'net', test: 'newContextValue' }
58 | PRE net uid:22 entryPoint:TCP context:{ _ns_name: 'net', test: 'newContextValue' }
59 | getting key:test=newContextValue in ns:net uid:22 active:{ _ns_name: 'net', test: 'newContextValue' }
60 | INIT net uid:-8 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
61 | INIT net uid:-9 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
62 | INIT net uid:-10 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
63 | INIT net uid:-11 parent:null provider:NONE active:{ _ns_name: 'net', test: 'newContextValue' }
64 | EXIT net uid:22 context: { _ns_name: 'net', test: 'newContextValue' }
65 | POST net uid:22 handle:TCP context:{ _ns_name: 'net', test: 'newContextValue' }
66 | ENTER net uid:-8 context: { _ns_name: 'net', test: 'newContextValue' }
67 | PRE net uid:-8 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
68 | EXIT net uid:-8 context: { _ns_name: 'net', test: 'newContextValue' }
69 | POST net uid:-8 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
70 | DESTROY net uid:-8 context:undefined active:null
71 | ENTER net uid:-9 context: { _ns_name: 'net', test: 'newContextValue' }
72 | PRE net uid:-9 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
73 | EXIT net uid:-9 context: { _ns_name: 'net', test: 'newContextValue' }
74 | POST net uid:-9 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
75 | DESTROY net uid:-9 context:undefined active:null
76 | ENTER net uid:-10 context: { _ns_name: 'net', test: 'newContextValue' }
77 | PRE net uid:-10 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
78 | EXIT net uid:-10 context: { _ns_name: 'net', test: 'newContextValue' }
79 | POST net uid:-10 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
80 | DESTROY net uid:-10 context:undefined active:null
81 | ENTER net uid:-11 context: { _ns_name: 'net', test: 'newContextValue' }
82 | PRE net uid:-11 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
83 | EXIT net uid:-11 context: { _ns_name: 'net', test: 'newContextValue' }
84 | POST net uid:-11 handle:NextTickWrap context:{ _ns_name: 'net', test: 'newContextValue' }
85 | DESTROY net uid:-11 context:undefined active:null
86 | ENTER net uid:25 context: { _ns_name: 'net', test: 'MONKEY' }
87 | PRE net uid:25 entryPoint:TCPConnectWrap context:{ _ns_name: 'net', test: 'MONKEY' }
88 | getting key:test=MONKEY in ns:net uid:25 active:{ _ns_name: 'net', test: 'MONKEY' }
89 | INIT net uid:-12 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
90 | .INIT net uid:-13 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
91 | INIT net uid:-14 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
92 | INIT net uid:-15 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
93 | INIT net uid:-16 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
94 | EXIT net uid:25 context: { _ns_name: 'net', test: 'MONKEY' }
95 | POST net uid:25 handle:TCPConnectWrap context:{ _ns_name: 'net', test: 'MONKEY' }
96 | ENTER net uid:-12 context: { _ns_name: 'net', test: 'MONKEY' }
97 | PRE net uid:-12 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
98 | EXIT net uid:-12 context: { _ns_name: 'net', test: 'MONKEY' }
99 | POST net uid:-12 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
100 | DESTROY net uid:-12 context:undefined active:null
101 | ENTER net uid:-13 context: { _ns_name: 'net', test: 'MONKEY' }
102 | PRE net uid:-13 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
103 | EXIT net uid:-13 context: { _ns_name: 'net', test: 'MONKEY' }
104 | POST net uid:-13 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
105 | DESTROY net uid:-13 context:undefined active:null
106 | ENTER net uid:-14 context: { _ns_name: 'net', test: 'MONKEY' }
107 | PRE net uid:-14 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
108 | EXIT net uid:-14 context: { _ns_name: 'net', test: 'MONKEY' }
109 | POST net uid:-14 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
110 | DESTROY net uid:-14 context:undefined active:null
111 | ENTER net uid:-15 context: { _ns_name: 'net', test: 'MONKEY' }
112 | PRE net uid:-15 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
113 | EXIT net uid:-15 context: { _ns_name: 'net', test: 'MONKEY' }
114 | POST net uid:-15 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
115 | DESTROY net uid:-15 context:undefined active:null
116 | ENTER net uid:-16 context: { _ns_name: 'net', test: 'MONKEY' }
117 | PRE net uid:-16 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
118 | EXIT net uid:-16 context: { _ns_name: 'net', test: 'MONKEY' }
119 | POST net uid:-16 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
120 | DESTROY net uid:-16 context:undefined active:null
121 | DESTROY net uid:25 context:undefined active:null
122 | PRE MISSING CONTEXT net uid:26 handle:TCP
123 | getting key:test=undefined in ns:net uid:26 active:null
124 | INIT net uid:-17 parent:null provider:NONE active:null
125 | INIT net uid:-18 parent:null provider:NONE active:null
126 | INIT net uid:-19 parent:null provider:NONE active:null
127 | .INIT net uid:-20 parent:null provider:NONE active:null
128 | INIT net uid:-21 parent:null provider:NONE active:null
129 | INIT net uid:-22 parent:null provider:NONE active:null
130 | INIT net uid:-23 parent:null provider:NONE active:null
131 | INIT net uid:-24 parent:null provider:NONE active:null
132 | INIT net uid:-25 parent:null provider:NONE active:null
133 | INIT net uid:-26 parent:null provider:NONE active:null
134 | INIT net uid:-27 parent:null provider:NONE active:null
135 | INIT net uid:-28 parent:null provider:NONE active:null
136 | INIT net uid:-29 parent:null provider:NONE active:null
137 | INIT net uid:-30 parent:null provider:NONE active:null
138 | INIT net uid:-31 parent:null provider:NONE active:null
139 | INIT net uid:-32 parent:null provider:NONE active:null
140 | INIT net uid:-33 parent:null provider:NONE active:null
141 | INIT net uid:-34 parent:null provider:NONE active:null
142 | INIT net uid:-35 parent:null provider:NONE active:null
143 | .INIT net uid:-36 parent:null provider:NONE active:null
144 | INIT net uid:-37 parent:null provider:NONE active:null
145 | INIT net uid:-38 parent:null provider:NONE active:null
146 | POST MISSING CONTEXT net uid:26 handle:TCP
147 | PRE MISSING CONTEXT net uid:-17 handle:NextTickWrap
148 | POST MISSING CONTEXT net uid:-17 handle:NextTickWrap
149 | DESTROY net uid:-17 context:undefined active:null
150 | PRE MISSING CONTEXT net uid:-18 handle:NextTickWrap
151 | POST MISSING CONTEXT net uid:-18 handle:NextTickWrap
152 | DESTROY net uid:-18 context:undefined active:null
153 | PRE MISSING CONTEXT net uid:-19 handle:NextTickWrap
154 | POST MISSING CONTEXT net uid:-19 handle:NextTickWrap
155 | DESTROY net uid:-19 context:undefined active:null
156 | PRE MISSING CONTEXT net uid:-20 handle:NextTickWrap
157 | POST MISSING CONTEXT net uid:-20 handle:NextTickWrap
158 | DESTROY net uid:-20 context:undefined active:null
159 | PRE MISSING CONTEXT net uid:-21 handle:NextTickWrap
160 | POST MISSING CONTEXT net uid:-21 handle:NextTickWrap
161 | DESTROY net uid:-21 context:undefined active:null
162 | PRE MISSING CONTEXT net uid:-22 handle:NextTickWrap
163 | POST MISSING CONTEXT net uid:-22 handle:NextTickWrap
164 | DESTROY net uid:-22 context:undefined active:null
165 | PRE MISSING CONTEXT net uid:-23 handle:NextTickWrap
166 | POST MISSING CONTEXT net uid:-23 handle:NextTickWrap
167 | DESTROY net uid:-23 context:undefined active:null
168 | PRE MISSING CONTEXT net uid:-24 handle:NextTickWrap
169 | POST MISSING CONTEXT net uid:-24 handle:NextTickWrap
170 | DESTROY net uid:-24 context:undefined active:null
171 | PRE MISSING CONTEXT net uid:-25 handle:NextTickWrap
172 | POST MISSING CONTEXT net uid:-25 handle:NextTickWrap
173 | DESTROY net uid:-25 context:undefined active:null
174 | PRE MISSING CONTEXT net uid:-26 handle:NextTickWrap
175 | POST MISSING CONTEXT net uid:-26 handle:NextTickWrap
176 | DESTROY net uid:-26 context:undefined active:null
177 | PRE MISSING CONTEXT net uid:-27 handle:NextTickWrap
178 | POST MISSING CONTEXT net uid:-27 handle:NextTickWrap
179 | DESTROY net uid:-27 context:undefined active:null
180 | PRE MISSING CONTEXT net uid:-28 handle:NextTickWrap
181 | POST MISSING CONTEXT net uid:-28 handle:NextTickWrap
182 | DESTROY net uid:-28 context:undefined active:null
183 | PRE MISSING CONTEXT net uid:-29 handle:NextTickWrap
184 | POST MISSING CONTEXT net uid:-29 handle:NextTickWrap
185 | DESTROY net uid:-29 context:undefined active:null
186 | PRE MISSING CONTEXT net uid:-30 handle:NextTickWrap
187 | POST MISSING CONTEXT net uid:-30 handle:NextTickWrap
188 | DESTROY net uid:-30 context:undefined active:null
189 | PRE MISSING CONTEXT net uid:-31 handle:NextTickWrap
190 | POST MISSING CONTEXT net uid:-31 handle:NextTickWrap
191 | DESTROY net uid:-31 context:undefined active:null
192 | PRE MISSING CONTEXT net uid:-32 handle:NextTickWrap
193 | POST MISSING CONTEXT net uid:-32 handle:NextTickWrap
194 | DESTROY net uid:-32 context:undefined active:null
195 | PRE MISSING CONTEXT net uid:-33 handle:NextTickWrap
196 | POST MISSING CONTEXT net uid:-33 handle:NextTickWrap
197 | DESTROY net uid:-33 context:undefined active:null
198 | PRE MISSING CONTEXT net uid:-34 handle:NextTickWrap
199 | POST MISSING CONTEXT net uid:-34 handle:NextTickWrap
200 | DESTROY net uid:-34 context:undefined active:null
201 | PRE MISSING CONTEXT net uid:-35 handle:NextTickWrap
202 | POST MISSING CONTEXT net uid:-35 handle:NextTickWrap
203 | DESTROY net uid:-35 context:undefined active:null
204 | PRE MISSING CONTEXT net uid:-36 handle:NextTickWrap
205 | POST MISSING CONTEXT net uid:-36 handle:NextTickWrap
206 | DESTROY net uid:-36 context:undefined active:null
207 | PRE MISSING CONTEXT net uid:-37 handle:NextTickWrap
208 | INIT net uid:27 parent:null provider:SHUTDOWNWRAP active:null
209 | POST MISSING CONTEXT net uid:-37 handle:NextTickWrap
210 | DESTROY net uid:-37 context:undefined active:null
211 | PRE MISSING CONTEXT net uid:-38 handle:NextTickWrap
212 | POST MISSING CONTEXT net uid:-38 handle:NextTickWrap
213 | DESTROY net uid:-38 context:undefined active:null
214 | DESTROY net uid:22 context:undefined active:null
215 | PRE MISSING CONTEXT net uid:27 handle:ShutdownWrap
216 | POST MISSING CONTEXT net uid:27 handle:ShutdownWrap
217 | DESTROY net uid:27 context:undefined active:null
218 | ENTER net uid:23 context: { _ns_name: 'net', test: 'MONKEY' }
219 | PRE net uid:23 entryPoint:TCP context:{ _ns_name: 'net', test: 'MONKEY' }
220 | getting key:test=MONKEY in ns:net uid:23 active:{ _ns_name: 'net', test: 'MONKEY' }
221 | INIT net uid:-39 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
222 | INIT net uid:-40 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
223 | INIT net uid:-41 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
224 | INIT net uid:-42 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
225 | INIT net uid:-43 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
226 | INIT net uid:-44 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
227 | INIT net uid:-45 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
228 | INIT net uid:-46 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
229 | INIT net uid:-47 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
230 | EXIT net uid:23 context: { _ns_name: 'net', test: 'MONKEY' }
231 | POST net uid:23 handle:TCP context:{ _ns_name: 'net', test: 'MONKEY' }
232 | ENTER net uid:-39 context: { _ns_name: 'net', test: 'MONKEY' }
233 | PRE net uid:-39 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
234 | EXIT net uid:-39 context: { _ns_name: 'net', test: 'MONKEY' }
235 | POST net uid:-39 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
236 | DESTROY net uid:-39 context:undefined active:null
237 | ENTER net uid:-40 context: { _ns_name: 'net', test: 'MONKEY' }
238 | PRE net uid:-40 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
239 | EXIT net uid:-40 context: { _ns_name: 'net', test: 'MONKEY' }
240 | POST net uid:-40 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
241 | DESTROY net uid:-40 context:undefined active:null
242 | .ENTER net uid:-41 context: { _ns_name: 'net', test: 'MONKEY' }
243 | PRE net uid:-41 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
244 | EXIT net uid:-41 context: { _ns_name: 'net', test: 'MONKEY' }
245 | POST net uid:-41 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
246 | DESTROY net uid:-41 context:undefined active:null
247 | ENTER net uid:-42 context: { _ns_name: 'net', test: 'MONKEY' }
248 | PRE net uid:-42 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
249 | EXIT net uid:-42 context: { _ns_name: 'net', test: 'MONKEY' }
250 | POST net uid:-42 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
251 | DESTROY net uid:-42 context:undefined active:null
252 | ENTER net uid:-43 context: { _ns_name: 'net', test: 'MONKEY' }
253 | PRE net uid:-43 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
254 | EXIT net uid:-43 context: { _ns_name: 'net', test: 'MONKEY' }
255 | POST net uid:-43 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
256 | DESTROY net uid:-43 context:undefined active:null
257 | ENTER net uid:-44 context: { _ns_name: 'net', test: 'MONKEY' }
258 | PRE net uid:-44 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
259 | EXIT net uid:-44 context: { _ns_name: 'net', test: 'MONKEY' }
260 | POST net uid:-44 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
261 | DESTROY net uid:-44 context:undefined active:null
262 | ENTER net uid:-45 context: { _ns_name: 'net', test: 'MONKEY' }
263 | PRE net uid:-45 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
264 | EXIT net uid:-45 context: { _ns_name: 'net', test: 'MONKEY' }
265 | POST net uid:-45 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
266 | DESTROY net uid:-45 context:undefined active:null
267 | ENTER net uid:-46 context: { _ns_name: 'net', test: 'MONKEY' }
268 | PRE net uid:-46 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
269 | EXIT net uid:-46 context: { _ns_name: 'net', test: 'MONKEY' }
270 | POST net uid:-46 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
271 | DESTROY net uid:-46 context:undefined active:null
272 | ENTER net uid:-47 context: { _ns_name: 'net', test: 'MONKEY' }
273 | PRE net uid:-47 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
274 | EXIT net uid:-47 context: { _ns_name: 'net', test: 'MONKEY' }
275 | POST net uid:-47 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
276 | DESTROY net uid:-47 context:undefined active:null
277 | ENTER net uid:23 context: { _ns_name: 'net', test: 'MONKEY' }
278 | PRE net uid:23 entryPoint:TCP context:{ _ns_name: 'net', test: 'MONKEY' }
279 | INIT net uid:-48 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
280 | INIT net uid:-49 parent:null provider:NONE active:{ _ns_name: 'net', test: 'MONKEY' }
281 | EXIT net uid:23 context: { _ns_name: 'net', test: 'MONKEY' }
282 | POST net uid:23 handle:TCP context:{ _ns_name: 'net', test: 'MONKEY' }
283 | ENTER net uid:-48 context: { _ns_name: 'net', test: 'MONKEY' }
284 | PRE net uid:-48 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
285 | EXIT net uid:-48 context: { _ns_name: 'net', test: 'MONKEY' }
286 | POST net uid:-48 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
287 | DESTROY net uid:-48 context:undefined active:null
288 | ENTER net uid:-49 context: { _ns_name: 'net', test: 'MONKEY' }
289 | PRE net uid:-49 entryPoint:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
290 | EXIT net uid:-49 context: { _ns_name: 'net', test: 'MONKEY' }
291 | POST net uid:-49 handle:NextTickWrap context:{ _ns_name: 'net', test: 'MONKEY' }
292 | DESTROY net uid:-49 context:undefined active:null
293 | ENTER net uid:23 context: { _ns_name: 'net', test: 'MONKEY' }
294 | PRE net uid:23 entryPoint:TCP context:{ _ns_name: 'net', test: 'MONKEY' }
295 | EXIT net uid:23 context: { _ns_name: 'net', test: 'MONKEY' }
296 | POST net uid:23 handle:TCP context:{ _ns_name: 'net', test: 'MONKEY' }
297 | DESTROY net uid:23 context:undefined active:null
298 | PRE MISSING CONTEXT net uid:26 handle:TCP
299 | INIT net uid:-50 parent:null provider:NONE active:null
300 | INIT net uid:-51 parent:null provider:NONE active:null
301 | INIT net uid:-52 parent:null provider:NONE active:null
302 |
303 | #PRE & POST uid:22 called multiple times
304 |
305 | POST MISSING CONTEXT net uid:26 handle:TCP
306 | PRE MISSING CONTEXT net uid:-50 handle:NextTickWrap
307 | POST MISSING CONTEXT net uid:-50 handle:NextTickWrap
308 | DESTROY net uid:-50 context:undefined active:null
309 | PRE MISSING CONTEXT net uid:-51 handle:NextTickWrap
310 | POST MISSING CONTEXT net uid:-51 handle:NextTickWrap
311 | DESTROY net uid:-51 context:undefined active:null
312 | PRE MISSING CONTEXT net uid:-52 handle:NextTickWrap
313 | POST MISSING CONTEXT net uid:-52 handle:NextTickWrap
314 | DESTROY net uid:-52 context:undefined active:null
315 | PRE MISSING CONTEXT net uid:26 handle:TCP
316 | POST MISSING CONTEXT net uid:26 handle:TCP
317 | DESTROY net uid:26 context:undefined active:null
318 | INIT net uid:-53 parent:null provider:NONE active:null
319 | INIT net uid:-54 parent:null provider:NONE active:null
320 | INIT net uid:-55 parent:null provider:NONE active:null
321 | INIT net uid:-56 parent:null provider:NONE active:null
322 |
--------------------------------------------------------------------------------
/logs/async-listener.log:
--------------------------------------------------------------------------------
1 | INIT ns:net id:2 active:null
2 | INIT ns:net id:2 active:null
3 | INIT ns:net id:2 active:{ test: 'MONKEY' }
4 | POST ns:net id:2 active:{ test: 'MONKEY' }
5 | EXIT context: { test: 'MONKEY' }
6 | PRE ns:net id:2 active:null
7 | ENTER context: { test: 'MONKEY' }
8 | POST ns:net id:2 active:{ test: 'MONKEY' }
9 | EXIT context: { test: 'MONKEY' }
10 | PRE ns:net id:2 active:null
11 | ENTER context: { test: 'MONKEY' }
12 | POST ns:net id:2 active:{ test: 'MONKEY' }
13 | EXIT context: { test: 'MONKEY' }
14 | PRE ns:net id:2 active:null
15 | ENTER context: { test: 'MONKEY' }
16 | POST ns:net id:2 active:{ test: 'MONKEY' }
17 | EXIT context: { test: 'MONKEY' }
18 | PRE ns:net id:2 active:null
19 | ENTER context: { test: 'newContextValue' }
20 | INIT ns:net id:2 active:{ test: 'newContextValue' }
21 | INIT ns:net id:2 active:{ test: 'newContextValue' }
22 | POST ns:net id:2 active:{ test: 'newContextValue' }
23 | EXIT context: { test: 'newContextValue' }
24 | PRE ns:net id:2 active:null
25 | ENTER context: { test: 'newContextValue' }
26 | POST ns:net id:2 active:{ test: 'newContextValue' }
27 | EXIT context: { test: 'newContextValue' }
28 | PRE ns:net id:2 active:null
29 | ENTER context: { test: 'newContextValue' }
30 | POST ns:net id:2 active:{ test: 'newContextValue' }
31 | EXIT context: { test: 'newContextValue' }
32 | PRE ns:net id:2 active:null
33 | ENTER context: { test: 'MONKEY' }
34 | INIT ns:net id:2 active:{ test: 'MONKEY' }
35 | POST ns:net id:2 active:{ test: 'MONKEY' }
36 | EXIT context: { test: 'MONKEY' }
37 | PRE ns:net id:2 active:null
38 | ENTER context: { test: 'MONKEY' }
39 | POST ns:net id:2 active:{ test: 'MONKEY' }
40 | EXIT context: { test: 'MONKEY' }
41 | PRE ns:net id:2 active:null
42 | ENTER context: { test: 'MONKEY' }
43 | INIT ns:net id:2 active:{ test: 'MONKEY' }
44 | INIT ns:net id:2 active:{ test: 'MONKEY' }
45 | POST ns:net id:2 active:{ test: 'MONKEY' }
46 | EXIT context: { test: 'MONKEY' }
47 | PRE ns:net id:2 active:null
48 | ENTER context: { test: 'MONKEY' }
49 | POST ns:net id:2 active:{ test: 'MONKEY' }
50 | EXIT context: { test: 'MONKEY' }
51 | PRE ns:net id:2 active:null
52 | ENTER context: { test: 'MONKEY' }
53 | POST ns:net id:2 active:{ test: 'MONKEY' }
54 | EXIT context: { test: 'MONKEY' }
55 | INIT ns:net id:2 active:null
56 | INIT ns:net id:2 active:null
57 | PRE ns:net id:2 active:null
58 | ENTER context: { test: 'newContextValue' }
59 | INIT ns:net id:2 active:{ test: 'newContextValue' }
60 | INIT ns:net id:2 active:{ test: 'newContextValue' }
61 | INIT ns:net id:2 active:{ test: 'newContextValue' }
62 | POST ns:net id:2 active:{ test: 'newContextValue' }
63 | EXIT context: { test: 'newContextValue' }
64 | PRE ns:net id:2 active:null
65 | ENTER context: { test: 'newContextValue' }
66 | POST ns:net id:2 active:{ test: 'newContextValue' }
67 | EXIT context: { test: 'newContextValue' }
68 | PRE ns:net id:2 active:null
69 | ENTER context: { test: 'newContextValue' }
70 | POST ns:net id:2 active:{ test: 'newContextValue' }
71 | EXIT context: { test: 'newContextValue' }
72 | PRE ns:net id:2 active:null
73 | ENTER context: { test: 'newContextValue' }
74 | POST ns:net id:2 active:{ test: 'newContextValue' }
75 | EXIT context: { test: 'newContextValue' }
76 | INIT ns:net id:2 active:null
77 | INIT ns:net id:2 active:null
78 | INIT ns:net id:2 active:null
79 | INIT ns:net id:2 active:null
80 | INIT ns:net id:2 active:null
81 | INIT ns:net id:2 active:null
82 | INIT ns:net id:2 active:null
83 | INIT ns:net id:2 active:null
84 | INIT ns:net id:2 active:null
85 | INIT ns:net id:2 active:null
86 | ENTER context: {}
87 | ENTER context: {}
88 | INIT ns:net id:2 active:{ test: 'newContextValue' }
89 | INIT ns:net id:2 active:{ test: 'newContextValue' }
90 | EXIT context: { test: 'newContextValue' }
91 | EXIT context: { test: 'originalValue' }
92 | PRE ns:net id:2 active:null
93 | ENTER context: { test: 'newContextValue' }
94 | ENTER context: {}
95 | INIT ns:net id:2 active:{ test: 'MONKEY' }
96 | INIT ns:net id:2 active:{ test: 'MONKEY' }
97 | INIT ns:net id:2 active:{ test: 'MONKEY' }
98 | EXIT context: { test: 'MONKEY' }
99 | POST ns:net id:2 active:{ test: 'newContextValue' }
100 | EXIT context: { test: 'newContextValue' }
101 | PRE ns:net id:2 active:null
102 | ENTER context: { test: 'MONKEY' }
103 | POST ns:net id:2 active:{ test: 'MONKEY' }
104 | EXIT context: { test: 'MONKEY' }
105 | PRE ns:net id:2 active:null
106 | ENTER context: { test: 'newContextValue' }
107 | INIT ns:net id:2 active:{ test: 'newContextValue' }
108 | INIT ns:net id:2 active:{ test: 'newContextValue' }
109 | POST ns:net id:2 active:{ test: 'newContextValue' }
110 | EXIT context: { test: 'newContextValue' }
111 | PRE ns:net id:2 active:null
112 | ENTER context: { test: 'newContextValue' }
113 | POST ns:net id:2 active:{ test: 'newContextValue' }
114 | EXIT context: { test: 'newContextValue' }
115 | PRE ns:net id:2 active:null
116 | ENTER context: { test: 'MONKEY' }
117 | INIT ns:net id:2 active:{ test: 'MONKEY' }
118 | INIT ns:net id:2 active:{ test: 'MONKEY' }
119 | INIT ns:net id:2 active:null
120 | INIT ns:net id:2 active:null
121 | INIT ns:net id:2 active:null
--------------------------------------------------------------------------------
/logs/namespaces-multiple-values.specs.log:
--------------------------------------------------------------------------------
1 | CREATING NAMESPACE ONE
2 | CREATING NAMESPACE TWO
3 |
4 | INIT ONE uid:-1 parent:null provider:NONE active:null
5 | INIT TWO uid:-1 parent:null provider:NONE active:null
6 |
7 | INIT ONE uid:-2 parent:null provider:NONE active:null
8 | INIT TWO uid:-2 parent:null provider:NONE active:null
9 | INIT ONE uid:4 parent:null provider:SIGNALWRAP active:null
10 | INIT TWO uid:4 parent:null provider:SIGNALWRAP active:null
11 | PRE MISSING CONTEXT ONE uid:-1 handle:NextTickWrap
12 | PRE MISSING CONTEXT TWO uid:-1 handle:NextTickWrap
13 | POST MISSING CONTEXT ONE uid:-1 handle:NextTickWrap
14 | POST MISSING CONTEXT TWO uid:-1 handle:NextTickWrap
15 | DESTROY ONE uid:-1 context:undefined active:null
16 | DESTROY TWO uid:-1 context:undefined active:null
17 | PRE MISSING CONTEXT ONE uid:-2 handle:NextTickWrap
18 | PRE MISSING CONTEXT TWO uid:-2 handle:NextTickWrap
19 | POST MISSING CONTEXT ONE uid:-2 handle:NextTickWrap
20 | POST MISSING CONTEXT TWO uid:-2 handle:NextTickWrap
21 | DESTROY ONE uid:-2 context:undefined active:null
22 | DESTROY TWO uid:-2 context:undefined active:null
23 | multiple namespaces handles them correctly
24 | INIT ONE uid:-3 parent:null provider:NONE active:null
25 | INIT TWO uid:-3 parent:null provider:NONE active:null
26 | PRE MISSING CONTEXT ONE uid:-3 handle:NextTickWrap
27 | PRE MISSING CONTEXT TWO uid:-3 handle:NextTickWrap
28 | POST MISSING CONTEXT ONE uid:-3 handle:NextTickWrap
29 | POST MISSING CONTEXT TWO uid:-3 handle:NextTickWrap
30 | DESTROY ONE uid:-3 context:undefined active:null
31 | DESTROY TWO uid:-3 context:undefined active:null
32 | CREATING Context: ONE 0 active:null
33 | CREATED Context: ONE 0 context:{ _ns_name: 'ONE', id: -3 }
34 | ENTER 0 ONE uid:-3 context: { _ns_name: 'ONE', id: -3 }
35 | BEFORE RUN: ONE 1 { _ns_name: 'ONE', id: -3 }
36 | CREATING Context: TWO 0 active:null
37 | CREATED Context: TWO 0 context:{ _ns_name: 'TWO', id: -3 }
38 | ENTER 0 TWO uid:-3 context: { _ns_name: 'TWO', id: -3 }
39 | BEFORE RUN: TWO 1 { _ns_name: 'TWO', id: -3 }
40 | SETTING KEY:name=tom1 in ns:ONE uid:-3 active:{ _ns_name: 'ONE', id: -3 }
41 | SETTING KEY:name=paul2 in ns:TWO uid:-3 active:{ _ns_name: 'TWO', id: -3 }
42 | INIT ONE uid:-4 parent:null provider:NONE active:{ _ns_name: 'ONE', id: -3, name: 'tom1' }
43 | INIT TWO uid:-4 parent:null provider:NONE active:{ _ns_name: 'TWO', id: -3, name: 'paul2' }
44 | AFTER RUN: TWO 1 { _ns_name: 'TWO', id: -3, name: 'paul2' }
45 | EXIT 1 TWO uid:-4 context: { _ns_name: 'TWO', id: -3, name: 'paul2' }
46 | AFTER RUN: ONE 1 { _ns_name: 'ONE', id: -3, name: 'tom1' }
47 | EXIT 1 ONE uid:-4 context: { _ns_name: 'ONE', id: -3, name: 'tom1' }
48 | PRE ONE uid:-4 handle:TimeoutWrap context:{ _ns_name: 'ONE', id: -3, name: 'tom1' }
49 | ENTER 0 ONE uid:-4 context: { _ns_name: 'ONE', id: -3, name: 'tom1' }
50 | PRE TWO uid:-4 handle:TimeoutWrap context:{ _ns_name: 'TWO', id: -3, name: 'paul2' }
51 | ENTER 0 TWO uid:-4 context: { _ns_name: 'TWO', id: -3, name: 'paul2' }
52 | CREATING Context: ONE 1 active:{ _ns_name: 'ONE', id: -3, name: 'tom1' }
53 | CREATED Context: ONE 1 context:{ _ns_name: 'ONE', id: -4 }
54 | ENTER 1 ONE uid:-4 context: { _ns_name: 'ONE', id: -4 }
55 | BEFORE RUN: ONE 2 { _ns_name: 'ONE', id: -4 }
56 | INIT ONE uid:-5 parent:null provider:NONE active:{ _ns_name: 'ONE', id: -4 }
57 | INIT TWO uid:-5 parent:null provider:NONE active:{ _ns_name: 'TWO', id: -3, name: 'paul2' }
58 | AFTER RUN: ONE 2 { _ns_name: 'ONE', id: -4 }
59 | EXIT 2 ONE uid:-5 context: { _ns_name: 'ONE', id: -4 }
60 | POST ONE uid:-4 handle:TimeoutWrap context:{ _ns_name: 'ONE', id: -3, name: 'tom1' }
61 | EXIT 1 ONE uid:-4 context: { _ns_name: 'ONE', id: -3, name: 'tom1' }
62 | POST TWO uid:-4 handle:TimeoutWrap context:{ _ns_name: 'TWO', id: -3, name: 'paul2' }
63 | EXIT 1 TWO uid:-4 context: { _ns_name: 'TWO', id: -3, name: 'paul2' }
64 | DESTROY ONE uid:-4 context:undefined active:null
65 | DESTROY TWO uid:-4 context:undefined active:null
66 | PRE ONE uid:-5 handle:NextTickWrap context:{ _ns_name: 'ONE', id: -4 }
67 | ENTER 0 ONE uid:-5 context: { _ns_name: 'ONE', id: -4 }
68 | PRE TWO uid:-5 handle:NextTickWrap context:{ _ns_name: 'TWO', id: -3, name: 'paul2' }
69 | ENTER 0 TWO uid:-5 context: { _ns_name: 'TWO', id: -3, name: 'paul2' }
70 | GETTING KEY:name=tom1 in ns:ONE uid:-5 active:{ _ns_name: 'ONE', id: -4 }
71 | GETTING KEY:name=paul2 in ns:TWO uid:-5 active:{ _ns_name: 'TWO', id: -3, name: 'paul2' }
72 | SETTING KEY:name=bob in ns:ONE uid:-5 active:{ _ns_name: 'ONE', id: -4 }
73 | SETTING KEY:name=alice in ns:TWO uid:-5 active:{ _ns_name: 'TWO', id: -3, name: 'paul2' }
74 | INIT ONE uid:-6 parent:null provider:NONE active:{ _ns_name: 'ONE', id: -4, name: 'bob' }
75 | INIT TWO uid:-6 parent:null provider:NONE active:{ _ns_name: 'TWO', id: -3, name: 'alice' }
76 | POST ONE uid:-5 handle:NextTickWrap context:{ _ns_name: 'ONE', id: -4, name: 'bob' }
77 | EXIT 1 ONE uid:-5 context: { _ns_name: 'ONE', id: -4, name: 'bob' }
78 | POST TWO uid:-5 handle:NextTickWrap context:{ _ns_name: 'TWO', id: -3, name: 'alice' }
79 | EXIT 1 TWO uid:-5 context: { _ns_name: 'TWO', id: -3, name: 'alice' }
80 | DESTROY ONE uid:-5 context:undefined active:null
81 | DESTROY TWO uid:-5 context:undefined active:null
82 | PRE ONE uid:-6 handle:TimeoutWrap context:{ _ns_name: 'ONE', id: -4, name: 'bob' }
83 | ENTER 0 ONE uid:-6 context: { _ns_name: 'ONE', id: -4, name: 'bob' }
84 | PRE TWO uid:-6 handle:TimeoutWrap context:{ _ns_name: 'TWO', id: -3, name: 'alice' }
85 | ENTER 0 TWO uid:-6 context: { _ns_name: 'TWO', id: -3, name: 'alice' }
86 | GETTING KEY:name=bob in ns:ONE uid:-6 active:{ _ns_name: 'ONE', id: -4, name: 'bob' }
87 | GETTING KEY:name=alice in ns:TWO uid:-6 active:{ _ns_name: 'TWO', id: -3, name: 'alice' }
88 | POST ONE uid:-6 handle:TimeoutWrap context:{ _ns_name: 'ONE', id: -4, name: 'bob' }
89 | EXIT 1 ONE uid:-6 context: { _ns_name: 'ONE', id: -4, name: 'bob' }
90 | POST TWO uid:-6 handle:TimeoutWrap context:{ _ns_name: 'TWO', id: -3, name: 'alice' }
91 | EXIT 1 TWO uid:-6 context: { _ns_name: 'TWO', id: -3, name: 'alice' }
92 | DESTROY ONE uid:-6 context:undefined active:null
93 | DESTROY TWO uid:-6 context:undefined active:null
94 | INIT ONE uid:-7 parent:null provider:NONE active:null
95 | INIT TWO uid:-7 parent:null provider:NONE active:null
96 | INIT ONE uid:-8 parent:null provider:NONE active:null
97 | INIT TWO uid:-8 parent:null provider:NONE active:null
98 | √ name tom1
99 | INIT ONE uid:-9 parent:null provider:NONE active:null
100 | INIT TWO uid:-9 parent:null provider:NONE active:null
101 | PRE MISSING CONTEXT ONE uid:-7 handle:NextTickWrap
102 | PRE MISSING CONTEXT TWO uid:-7 handle:NextTickWrap
103 | POST MISSING CONTEXT ONE uid:-7 handle:NextTickWrap
104 | POST MISSING CONTEXT TWO uid:-7 handle:NextTickWrap
105 | DESTROY ONE uid:-7 context:undefined active:null
106 | DESTROY TWO uid:-7 context:undefined active:null
107 | PRE MISSING CONTEXT ONE uid:-8 handle:NextTickWrap
108 | PRE MISSING CONTEXT TWO uid:-8 handle:NextTickWrap
109 | POST MISSING CONTEXT ONE uid:-8 handle:NextTickWrap
110 | POST MISSING CONTEXT TWO uid:-8 handle:NextTickWrap
111 | DESTROY ONE uid:-8 context:undefined active:null
112 | DESTROY TWO uid:-8 context:undefined active:null
113 | PRE MISSING CONTEXT ONE uid:-9 handle:NextTickWrap
114 | PRE MISSING CONTEXT TWO uid:-9 handle:NextTickWrap
115 | POST MISSING CONTEXT ONE uid:-9 handle:NextTickWrap
116 | POST MISSING CONTEXT TWO uid:-9 handle:NextTickWrap
117 | DESTROY ONE uid:-9 context:undefined active:null
118 | DESTROY TWO uid:-9 context:undefined active:null
119 | INIT ONE uid:-10 parent:null provider:NONE active:null
120 | INIT TWO uid:-10 parent:null provider:NONE active:null
121 | INIT ONE uid:-11 parent:null provider:NONE active:null
122 | INIT TWO uid:-11 parent:null provider:NONE active:null
123 | √ name paul2
124 | INIT ONE uid:-12 parent:null provider:NONE active:null
125 | INIT TWO uid:-12 parent:null provider:NONE active:null
126 | PRE MISSING CONTEXT ONE uid:-10 handle:NextTickWrap
127 | PRE MISSING CONTEXT TWO uid:-10 handle:NextTickWrap
128 | POST MISSING CONTEXT ONE uid:-10 handle:NextTickWrap
129 | POST MISSING CONTEXT TWO uid:-10 handle:NextTickWrap
130 | DESTROY ONE uid:-10 context:undefined active:null
131 | DESTROY TWO uid:-10 context:undefined active:null
132 | PRE MISSING CONTEXT ONE uid:-11 handle:NextTickWrap
133 | PRE MISSING CONTEXT TWO uid:-11 handle:NextTickWrap
134 | POST MISSING CONTEXT ONE uid:-11 handle:NextTickWrap
135 | POST MISSING CONTEXT TWO uid:-11 handle:NextTickWrap
136 | DESTROY ONE uid:-11 context:undefined active:null
137 | DESTROY TWO uid:-11 context:undefined active:null
138 | PRE MISSING CONTEXT ONE uid:-12 handle:NextTickWrap
139 | PRE MISSING CONTEXT TWO uid:-12 handle:NextTickWrap
140 | POST MISSING CONTEXT ONE uid:-12 handle:NextTickWrap
141 | POST MISSING CONTEXT TWO uid:-12 handle:NextTickWrap
142 | DESTROY ONE uid:-12 context:undefined active:null
143 | DESTROY TWO uid:-12 context:undefined active:null
144 | INIT ONE uid:-13 parent:null provider:NONE active:null
145 | INIT TWO uid:-13 parent:null provider:NONE active:null
146 | INIT ONE uid:-14 parent:null provider:NONE active:null
147 | INIT TWO uid:-14 parent:null provider:NONE active:null
148 | √ name bob
149 | INIT ONE uid:-15 parent:null provider:NONE active:null
150 | INIT TWO uid:-15 parent:null provider:NONE active:null
151 | PRE MISSING CONTEXT ONE uid:-13 handle:NextTickWrap
152 | PRE MISSING CONTEXT TWO uid:-13 handle:NextTickWrap
153 | POST MISSING CONTEXT ONE uid:-13 handle:NextTickWrap
154 | POST MISSING CONTEXT TWO uid:-13 handle:NextTickWrap
155 | DESTROY ONE uid:-13 context:undefined active:null
156 | DESTROY TWO uid:-13 context:undefined active:null
157 | PRE MISSING CONTEXT ONE uid:-14 handle:NextTickWrap
158 | PRE MISSING CONTEXT TWO uid:-14 handle:NextTickWrap
159 | POST MISSING CONTEXT ONE uid:-14 handle:NextTickWrap
160 | POST MISSING CONTEXT TWO uid:-14 handle:NextTickWrap
161 | DESTROY ONE uid:-14 context:undefined active:null
162 | DESTROY TWO uid:-14 context:undefined active:null
163 | PRE MISSING CONTEXT ONE uid:-15 handle:NextTickWrap
164 | PRE MISSING CONTEXT TWO uid:-15 handle:NextTickWrap
165 | POST MISSING CONTEXT ONE uid:-15 handle:NextTickWrap
166 | POST MISSING CONTEXT TWO uid:-15 handle:NextTickWrap
167 | DESTROY ONE uid:-15 context:undefined active:null
168 | DESTROY TWO uid:-15 context:undefined active:null
169 | INIT ONE uid:-16 parent:null provider:NONE active:null
170 | INIT TWO uid:-16 parent:null provider:NONE active:null
171 | INIT ONE uid:-17 parent:null provider:NONE active:null
172 | INIT TWO uid:-17 parent:null provider:NONE active:null
173 | √ name alice
174 | INIT ONE uid:-18 parent:null provider:NONE active:null
175 | INIT TWO uid:-18 parent:null provider:NONE active:null
176 | PRE MISSING CONTEXT ONE uid:-16 handle:NextTickWrap
177 | PRE MISSING CONTEXT TWO uid:-16 handle:NextTickWrap
178 | POST MISSING CONTEXT ONE uid:-16 handle:NextTickWrap
179 | POST MISSING CONTEXT TWO uid:-16 handle:NextTickWrap
180 | DESTROY ONE uid:-16 context:undefined active:null
181 | DESTROY TWO uid:-16 context:undefined active:null
182 | PRE MISSING CONTEXT ONE uid:-17 handle:NextTickWrap
183 | PRE MISSING CONTEXT TWO uid:-17 handle:NextTickWrap
184 | POST MISSING CONTEXT ONE uid:-17 handle:NextTickWrap
185 | POST MISSING CONTEXT TWO uid:-17 handle:NextTickWrap
186 | DESTROY ONE uid:-17 context:undefined active:null
187 | DESTROY TWO uid:-17 context:undefined active:null
188 | PRE MISSING CONTEXT ONE uid:-18 handle:NextTickWrap
189 | PRE MISSING CONTEXT TWO uid:-18 handle:NextTickWrap
190 | POST MISSING CONTEXT ONE uid:-18 handle:NextTickWrap
191 | POST MISSING CONTEXT TWO uid:-18 handle:NextTickWrap
192 | DESTROY ONE uid:-18 context:undefined active:null
193 | DESTROY TWO uid:-18 context:undefined active:null
194 |
195 | INIT ONE uid:-19 parent:null provider:NONE active:null
196 | INIT TWO uid:-19 parent:null provider:NONE active:null
197 | PRE MISSING CONTEXT ONE uid:-19 handle:NextTickWrap
198 | PRE MISSING CONTEXT TWO uid:-19 handle:NextTickWrap
199 | POST MISSING CONTEXT ONE uid:-19 handle:NextTickWrap
200 | POST MISSING CONTEXT TWO uid:-19 handle:NextTickWrap
201 | DESTROY ONE uid:-19 context:undefined active:null
202 | DESTROY TWO uid:-19 context:undefined active:null
203 |
204 | INIT ONE uid:-20 parent:null provider:NONE active:null
205 | INIT TWO uid:-20 parent:null provider:NONE active:null
206 | 4 passing (533ms)
207 | INIT ONE uid:-21 parent:null provider:NONE active:null
208 | INIT TWO uid:-21 parent:null provider:NONE active:null
209 |
210 | INIT ONE uid:-22 parent:null provider:NONE active:null
211 | INIT TWO uid:-22 parent:null provider:NONE active:null
212 | INIT ONE uid:-23 parent:null provider:NONE active:null
213 | INIT TWO uid:-23 parent:null provider:NONE active:null
214 | INIT ONE uid:-24 parent:null provider:NONE active:null
215 | INIT TWO uid:-24 parent:null provider:NONE active:null
216 | PRE MISSING CONTEXT ONE uid:-20 handle:NextTickWrap
217 | PRE MISSING CONTEXT TWO uid:-20 handle:NextTickWrap
218 | POST MISSING CONTEXT ONE uid:-20 handle:NextTickWrap
219 | POST MISSING CONTEXT TWO uid:-20 handle:NextTickWrap
220 | DESTROY ONE uid:-20 context:undefined active:null
221 | DESTROY TWO uid:-20 context:undefined active:null
222 | PRE MISSING CONTEXT ONE uid:-21 handle:NextTickWrap
223 | PRE MISSING CONTEXT TWO uid:-21 handle:NextTickWrap
224 | POST MISSING CONTEXT ONE uid:-21 handle:NextTickWrap
225 | POST MISSING CONTEXT TWO uid:-21 handle:NextTickWrap
226 | DESTROY ONE uid:-21 context:undefined active:null
227 | DESTROY TWO uid:-21 context:undefined active:null
228 | PRE MISSING CONTEXT ONE uid:-22 handle:NextTickWrap
229 | PRE MISSING CONTEXT TWO uid:-22 handle:NextTickWrap
230 | POST MISSING CONTEXT ONE uid:-22 handle:NextTickWrap
231 | POST MISSING CONTEXT TWO uid:-22 handle:NextTickWrap
232 | DESTROY ONE uid:-22 context:undefined active:null
233 | DESTROY TWO uid:-22 context:undefined active:null
234 | PRE MISSING CONTEXT ONE uid:-23 handle:NextTickWrap
235 | PRE MISSING CONTEXT TWO uid:-23 handle:NextTickWrap
236 | POST MISSING CONTEXT ONE uid:-23 handle:NextTickWrap
237 | POST MISSING CONTEXT TWO uid:-23 handle:NextTickWrap
238 | DESTROY ONE uid:-23 context:undefined active:null
239 | DESTROY TWO uid:-23 context:undefined active:null
240 | PRE MISSING CONTEXT ONE uid:-24 handle:NextTickWrap
241 | PRE MISSING CONTEXT TWO uid:-24 handle:NextTickWrap
242 |
--------------------------------------------------------------------------------
/logs/providers.json:
--------------------------------------------------------------------------------
1 | {
2 | "NONE": 0,
3 | "CRYPTO": 1,
4 | "FSEVENTWRAP": 2,
5 | "FSREQWRAP": 3,
6 | "GETADDRINFOREQWRAP": 4,
7 | "GETNAMEINFOREQWRAP": 5,
8 | "HTTPPARSER": 6,
9 | "JSSTREAM": 7,
10 | "PIPEWRAP": 8,
11 | "PIPECONNECTWRAP": 9,
12 | "PROCESSWRAP": 10,
13 | "QUERYWRAP": 11,
14 | "SHUTDOWNWRAP": 12,
15 | "SIGNALWRAP": 13,
16 | "STATWATCHER": 14,
17 | "TCPWRAP": 15,
18 | "TCPCONNECTWRAP": 16,
19 | "TIMERWRAP": 17,
20 | "TLSWRAP": 18,
21 | "TTYWRAP": 19,
22 | "UDPWRAP": 20,
23 | "UDPSENDWRAP": 21,
24 | "WRITEWRAP": 22,
25 | "ZLIB": 23
26 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cls-hooked",
3 | "version": "4.3.0",
4 | "description": "CLS using AsyncWrap instead of async-listener - Node >= 4.7.0",
5 | "main": "index.js",
6 | "files": [
7 | "index.js",
8 | "context.js",
9 | "context-legacy.js"
10 | ],
11 | "scripts": {
12 | "test": "mocha test/*.js & tap test/tap/*.tap.js",
13 | "test-mocha": "mocha test/*.js",
14 | "test-tap": "tap test/tap/*.tap.js",
15 | "debug": "node --nolazy --debug-brk=5858 "
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "https://github.com/jeff-lewis/cls-hooked.git"
20 | },
21 | "keywords": [
22 | "threading",
23 | "shared",
24 | "context"
25 | ],
26 | "author": "Forrest L Norvell ",
27 | "contributors": [
28 | "Tim Caswell ",
29 | "Forrest L Norvell ",
30 | "Jeff Lewis "
31 | ],
32 | "license": "BSD-2-Clause",
33 | "engineStrict": false,
34 | "engines": {
35 | "node": "^4.7 || >=6.9 || >=7.3 || >=8.2.1"
36 | },
37 | "dependencies": {
38 | "async-hook-jl": "^1.7.6",
39 | "emitter-listener": "^1.0.1"
40 | },
41 | "devDependencies": {
42 | "chai": "^4.1.0",
43 | "mocha": "^6.2.2",
44 | "semver": "^6.3.0",
45 | "sinon": "^7.5.0",
46 | "sinon-chai": "^3.3.0",
47 | "superagent": "^5.1.2",
48 | "tap": "^10.7.3"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/test/async-context.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const expect = require('chai').expect;
4 | const cls = require('../index.js');
5 |
6 | describe("cls simple async local context", function () {
7 |
8 | it("asynchronously propagating state with local-context", function (done) {
9 | var namespace = cls.createNamespace('namespace');
10 | expect(process.namespaces.namespace, "namespace has been created");
11 |
12 | namespace.run(function () {
13 | namespace.set('test', 1337);
14 | expect(namespace.get('test')).equal(1337, "namespace is working");
15 | done();
16 | });
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/test/async-no-run-queue-multiple.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const expect = require('chai').expect;
4 | const cls = require('../index.js');
5 |
6 | describe("cls edges and regression testing", function () {
7 |
8 | it("minimized test case that caused #6011 patch to fail", function (done) {
9 | var n = cls.createNamespace("test");
10 | console.log('+');
11 | // when the flaw was in the patch, commenting out this line would fix things:
12 | process.nextTick(function () { console.log('!'); });
13 |
14 | expect(!n.get('state'), "state should not yet be visible");
15 |
16 | n.run(function () {
17 | n.set('state', true);
18 | expect(n.get('state'), "state should be visible");
19 |
20 | process.nextTick(function () {
21 | expect(n.get('state'), "state should be visible");
22 | done();
23 | });
24 | });
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/test/http-agent-break.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const chai = require('chai');
4 | const should = chai.should();
5 |
6 | const superagent = require('superagent');
7 |
8 | const cls = require('./../index');
9 | const http = require('http');
10 |
11 | const keepAlive = process.env.KEEP_ALIVE !== '0';
12 |
13 | describe('cls with http Agent', () => {
14 |
15 | let httpAgent;
16 | let namespace = cls.createNamespace('httpAgent');
17 |
18 | before(() => {
19 | httpAgent = new http.Agent({
20 | keepAlive: keepAlive,
21 | maxSockets: 1,
22 | keepAliveMsecs: 30000
23 | });
24 | });
25 |
26 |
27 | describe('when making two http requests', ()=> {
28 |
29 | let innerRequestContextValue;
30 |
31 | it('should retain context during first', (done)=> {
32 | doClsAction(123, () => {
33 | should.exist(innerRequestContextValue)
34 | innerRequestContextValue.should.equal(123);
35 | done();
36 | });
37 | });
38 |
39 |
40 | it('should retain context during second', (done)=> {
41 | doClsAction(456, () => {
42 | should.exist(innerRequestContextValue)
43 | innerRequestContextValue.should.equal(456);
44 | done();
45 | });
46 | });
47 |
48 |
49 | function doClsAction(id, cb) {
50 | namespace.run(function () {
51 | //var xid = Math.floor(Math.random() * 1000);
52 | var xid = id;
53 | namespace.set('xid', xid);
54 | //process._rawDebug('before calling httpGetRequest: xid value', namespace.get('xid'));
55 |
56 | httpGetRequest(function (e) {
57 | //process._rawDebug('returned from action xid value', namespace.get('xid'), 'expected', xid);
58 | innerRequestContextValue = namespace.get('xid');
59 | //assert.equal(namespace.get('xid'), xid);
60 | cb(e);
61 | });
62 |
63 | });
64 | }
65 |
66 |
67 | function httpGetRequest(cb) {
68 |
69 | //https://github.com/othiym23/node-continuation-local-storage/issues/71
70 | namespace.bindEmitter(superagent.Request.super_.super_.prototype);
71 |
72 | var req = superagent['get']('http://www.google.com');
73 |
74 | if (keepAlive) {
75 | //process._rawDebug('Keep alive ENABLED, setting http agent');
76 | req.agent(httpAgent);
77 | }
78 |
79 | req.end(function (err, res) {
80 | if (err) {
81 | cb(err);
82 | } else {
83 | //process._rawDebug('http get status', res.status);
84 | cb(null, {status: res.status, statusText: res.text, obj: res.body});
85 | }
86 | });
87 | }
88 |
89 | });
90 |
91 | });
92 |
--------------------------------------------------------------------------------
/test/http-events.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var DATUM1 = 'Hello';
4 | var DATUM2 = 'GoodBye';
5 | var TEST_VALUE = 0x1337;
6 | var PORT = 55667;
7 |
8 | var chai = require('chai');
9 | var sinon = require('sinon');
10 | var sinonChai = require('sinon-chai');
11 | chai.should();
12 | chai.use(sinonChai);
13 |
14 | describe('cls with http connections', function () {
15 |
16 | this.timeout(1000);
17 |
18 | let http = require('http');
19 | let cls = require('../index');
20 |
21 | describe('client server', function clientServerTest() {
22 |
23 | var namespace = cls.createNamespace('http');
24 |
25 | var requestSpy = sinon.spy();
26 | var requestDataSpy = sinon.spy();
27 | var responseSpy = sinon.spy();
28 | var responseDataSpy = sinon.spy();
29 | var finalContextValue;
30 |
31 | before((done) => {
32 |
33 | namespace.run(() => {
34 | namespace.set('test', TEST_VALUE);
35 | var server = http.createServer();
36 |
37 | server.on('request', function OnServerConnection(req, res) {
38 | requestSpy(namespace.get('test'));
39 |
40 | req.on('data', function OnServerSocketData(data) {
41 | requestDataSpy(data.toString('utf-8'), namespace.get('test'));
42 | server.close();
43 | res.end(DATUM2);
44 | });
45 | });
46 |
47 | server.listen(PORT, function OnServerListen() {
48 |
49 | namespace.run(() => {
50 |
51 | namespace.set('test', 'MONKEY');
52 |
53 | var request = http.request({host: 'localhost', port: PORT, method: 'POST'}, function OnClientConnect(res) {
54 |
55 | responseSpy(namespace.get('test'));
56 |
57 | res.on('data', function OnClientSocketData(reponseData) {
58 | responseDataSpy(reponseData.toString('utf-8'), namespace.get('test'));
59 | done();
60 | });
61 | });
62 |
63 | request.write(DATUM1);
64 | });
65 |
66 | });
67 |
68 | finalContextValue = namespace.get('test');
69 | });
70 |
71 |
72 | })
73 |
74 | it('server request event should be called', () => {
75 | requestSpy.called.should.be.true;
76 | });
77 |
78 | it('server request event should receive data', () => {
79 | requestSpy.should.have.been.calledWith(TEST_VALUE);
80 | });
81 |
82 | it('server request data event should be called', () => {
83 | requestDataSpy.called.should.be.true;
84 | });
85 |
86 | it('server request data event should receive data', () => {
87 | requestDataSpy.should.have.been.calledWith(DATUM1, TEST_VALUE);
88 | });
89 |
90 | it('client data event should be called', () => {
91 | responseSpy.called.should.be.true;
92 | });
93 |
94 | it('client data event should receive data', () => {
95 | responseDataSpy.should.have.been.calledWith(DATUM2, 'MONKEY');
96 | });
97 |
98 | it('final context value should be ' + TEST_VALUE, () => {
99 | finalContextValue.should.be.equal(TEST_VALUE);
100 | });
101 |
102 | });
103 | });
104 |
--------------------------------------------------------------------------------
/test/namespaces-multiple-values.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('mocha');
4 | const chai = require('chai');
5 | const util = require('util');
6 | chai.should();
7 |
8 | const cls = require('../index.js');
9 |
10 | describe('multiple namespaces handles them correctly', () => {
11 |
12 | let test1Val;
13 | let test2Val;
14 | let test3Val;
15 | let test4Val;
16 |
17 | let ns1 = cls.createNamespace('ONE');
18 | let ns2 = cls.createNamespace('TWO');
19 |
20 |
21 | before((done) => {
22 |
23 | ns1.run(() => {
24 | ns2.run(() => {
25 |
26 | ns1.set('name', 'tom1');
27 | ns2.set('name', 'paul2');
28 |
29 | setTimeout(() => {
30 |
31 | ns1.run(() => {
32 |
33 | process.nextTick(() => {
34 |
35 | test1Val = ns1.get('name');
36 | process._rawDebug(util.inspect(ns1), true);
37 |
38 | test2Val = ns2.get('name');
39 | process._rawDebug(util.inspect(ns2), true);
40 |
41 | ns1.set('name', 'bob');
42 | ns2.set('name', 'alice');
43 |
44 | setTimeout(function() {
45 | test3Val = ns1.get('name');
46 | test4Val = ns2.get('name');
47 | done();
48 | });
49 |
50 | });
51 |
52 | });
53 |
54 | });
55 |
56 | });
57 | });
58 |
59 | });
60 |
61 | it('name tom1', () => {
62 | test1Val.should.equal('tom1');
63 | });
64 |
65 | it('name paul2', () => {
66 | test2Val.should.equal('paul2');
67 | });
68 |
69 | it('name bob', () => {
70 | test3Val.should.equal('bob');
71 | });
72 |
73 | it('name alice', () => {
74 | test4Val.should.equal('alice');
75 | });
76 |
77 | });
78 |
79 |
--------------------------------------------------------------------------------
/test/namespaces.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const chai = require('chai');
4 | const should = chai.should();
5 |
6 | const context = require('../index.js');
7 |
8 | chai.config.includeStack = true;
9 |
10 | describe('cls namespace management', () => {
11 |
12 | it('name is required', () => {
13 | should.Throw(() => {
14 | context.createNamespace();
15 | });
16 | });
17 |
18 | let namespaceTest;
19 | before(() => {
20 | namespaceTest = context.createNamespace('test');
21 | });
22 |
23 | it('namespace is returned upon creation', () => {
24 | should.exist(namespaceTest);
25 | });
26 |
27 | it('namespace lookup works', () => {
28 | should.exist(context.getNamespace('test'));
29 | context.getNamespace('test').should.be.equal(namespaceTest);
30 | });
31 |
32 | it('allows resetting namespaces', () => {
33 | should.not.Throw(() => {
34 | context.reset();
35 | });
36 | });
37 |
38 | it('namespaces have been reset', () => {
39 | Object.keys(process.namespaces).length.should.equal(0);
40 | });
41 |
42 | it('namespace is available from global', () => {
43 | context.createNamespace('another');
44 | should.exist(process.namespaces.another);
45 | });
46 |
47 | it('destroying works', () => {
48 | should.not.Throw(() => {
49 | context.destroyNamespace('another');
50 | });
51 | });
52 |
53 | it('namespace has been removed', () => {
54 | should.not.exist(process.namespaces.another);
55 | });
56 |
57 | });
58 |
--------------------------------------------------------------------------------
/test/net-events.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('mocha');
4 | const chai = require('chai');
5 | const should = chai.should();
6 | const net = require('net');
7 | const cls = require('../index.js');
8 |
9 | describe('cls with net connection', () => {
10 |
11 | let namespace = cls.createNamespace('net');
12 | let testValue1;
13 | let testValue2;
14 | let testValue3;
15 | let testValue4;
16 |
17 | before(function(done) {
18 |
19 | let serverDone = false;
20 | let clientDone = false;
21 |
22 | namespace.run(() => {
23 | namespace.set('test', 'originalValue');
24 |
25 | let server;
26 | namespace.run(() => {
27 | namespace.set('test', 'newContextValue');
28 |
29 | server = net.createServer((socket) => {
30 | //namespace.bindEmitter(socket);
31 |
32 | testValue1 = namespace.get('test');
33 |
34 | socket.on('data', () => {
35 | testValue2 = namespace.get('test');
36 | server.close();
37 | socket.end('GoodBye');
38 |
39 | serverDone = true;
40 | checkDone();
41 | });
42 |
43 | });
44 |
45 | server.listen(() => {
46 | const address = server.address();
47 | namespace.run(() => {
48 | namespace.set('test', 'MONKEY');
49 |
50 | const client = net.connect(address.port, () => {
51 | //namespace.bindEmitter(client);
52 | testValue3 = namespace.get('test');
53 | client.write('Hello');
54 |
55 | client.on('data', () => {
56 | testValue4 = namespace.get('test');
57 | clientDone = true;
58 | checkDone();
59 | });
60 |
61 | });
62 | });
63 | });
64 | });
65 | });
66 |
67 | function checkDone() {
68 | if (serverDone && clientDone) {
69 | done();
70 | }
71 | }
72 |
73 | });
74 |
75 | it('value newContextValue', () => {
76 | should.exist(testValue1);
77 | testValue1.should.equal('newContextValue');
78 | });
79 |
80 | it('value newContextValue 2', () => {
81 | should.exist(testValue2);
82 | testValue2.should.equal('newContextValue');
83 | });
84 |
85 | it('value MONKEY', () => {
86 | should.exist(testValue3);
87 | testValue3.should.equal('MONKEY');
88 | });
89 |
90 | it('value MONKEY 2', () => {
91 | should.exist(testValue4);
92 | testValue4.should.equal('MONKEY');
93 | });
94 |
95 | });
96 |
--------------------------------------------------------------------------------
/test/net-events2.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const expect = require('chai').expect;
4 |
5 | const net = require('net');
6 | const cls = require('../index.js');
7 |
8 | describe('cls with net connection 2', function() {
9 |
10 | const DATUM1 = 'Hello';
11 | const DATUM2 = 'GoodBye';
12 | const TEST_VALUE = 0x1337;
13 | const TEST_VALUE2 = 'MONKEY';
14 | const keyName = 'netTest2';
15 |
16 | it('client server', function(done) {
17 | const namespace = cls.createNamespace('net2');
18 |
19 | namespace.run(
20 | function namespaceRun1(ctx) {
21 | namespace.set(keyName, TEST_VALUE);
22 | expect(namespace.get(keyName)).equal(ctx.netTest2, 'context should be the same');
23 | const server = net.createServer();
24 |
25 | server.on('connection', function OnServerConnection(socket) {
26 | expect(namespace.get(keyName)).equal(TEST_VALUE, 'state has been mutated');
27 |
28 | socket.on('data', function OnServerSocketData(data) {
29 | data = data.toString('utf-8');
30 | expect(data).equal(DATUM1, 'should get DATUM1');
31 | expect(namespace.get(keyName)).equal(TEST_VALUE, 'state is still preserved');
32 |
33 | socket.end(DATUM2);
34 | server.close();
35 | });
36 | }
37 | );
38 |
39 | server.listen(function onServerListen() {
40 | namespace.run(
41 | function namespaceRun2(ctx) {
42 | namespace.set(keyName, TEST_VALUE2);
43 | expect(namespace.get(keyName)).equal(ctx.netTest2, 'context should be the same');
44 |
45 | const port = server.address().port;
46 | const client = net.connect(port, function OnClientConnect() {
47 | expect(namespace.get(keyName)).equal(TEST_VALUE2, 'state preserved for client connection');
48 | client.on('data', function OnClientSocketData(data) {
49 | data = data.toString('utf-8');
50 | expect(data).equal(DATUM2, 'should get DATUM1');
51 | expect(namespace.get(keyName)).equal(TEST_VALUE2, 'state preserved for client data');
52 | });
53 |
54 | client.on('close', function onClientSocketClose() {
55 | done();
56 | });
57 |
58 | client.write(DATUM1);
59 | });
60 | }
61 | );
62 | });
63 | }
64 | );
65 | });
66 | });
67 |
--------------------------------------------------------------------------------
/test/promise-context-convention.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('mocha');
4 | const chai = require('chai');
5 | const should = chai.should();
6 |
7 | const context = require('../index.js');
8 |
9 | /**
10 | * See https://github.com/othiym23/node-continuation-local-storage/issues/64
11 | */
12 | describe('Promise context convention', () => {
13 |
14 | let promise;
15 | let ns = context.createNamespace('PromiseConventionNS');
16 | let conventionId = 0;
17 |
18 | before((done) => {
19 | ns.run(() => {
20 | ns.set('test', 2);
21 | promise = new Promise((resolve) => {
22 | ns.run(() => {
23 | ns.set('test', 1);
24 | resolve();
25 | });
26 | });
27 | });
28 |
29 | ns.run(() => {
30 | ns.set('test', 3);
31 | promise.then(() => {
32 | //console.log('This Promise implementation follows convention ' + ns.get('test'));
33 | conventionId = ns.get('test');
34 | done();
35 | });
36 | });
37 |
38 | });
39 |
40 | it('convention should be 3', () => {
41 | should.equal(conventionId, 3);
42 | });
43 |
44 | });
45 |
--------------------------------------------------------------------------------
/test/tap/async-context.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const tap = require('tap');
4 | const test = tap.test;
5 | const createNamespace = require('../../index.js').createNamespace;
6 |
7 | test("asynchronously propagating state with local-context-domains", function (t) {
8 | t.plan(2);
9 |
10 | var namespace = createNamespace('namespace');
11 | t.ok(process.namespaces.namespace, "namespace has been created");
12 |
13 | namespace.run(function () {
14 | namespace.set('test', 1337);
15 | t.equal(namespace.get('test'), 1337, "namespace is working");
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/test/tap/async-no-run-queue-multiple.tap.js:
--------------------------------------------------------------------------------
1 | const test = require('tap').test;
2 | const cls = require('../../index.js');
3 |
4 | test("minimized test case that caused #6011 patch to fail", function (t) {
5 | t.plan(3);
6 |
7 | console.log('+');
8 | // when the flaw was in the patch, commenting out this line would fix things:
9 | process.nextTick(function () { console.log('!'); });
10 |
11 | var n = cls.createNamespace("test");
12 | t.ok(!n.get('state'), "state should not yet be visible");
13 |
14 | n.run(function () {
15 | n.set('state', true);
16 | t.ok(n.get('state'), "state should be visible");
17 |
18 | process.nextTick(function () {
19 | t.ok(n.get('state'), "state should be visible");
20 | //console.log(cls.trace);
21 | });
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/test/tap/bind-emitter-multiple.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var test = require('tap').test;
4 | var EventEmitter = require('events').EventEmitter;
5 | var cls = require('../../index.js');
6 | const util = require('util');
7 |
8 | test("event emitters bound to CLS context", function(t) {
9 | t.plan(1);
10 |
11 | t.test("emitter bound to multiple namespaces handles them correctly", function(t) {
12 | t.plan(6);
13 |
14 | var ee = new EventEmitter();
15 | var ns1 = cls.createNamespace('1');
16 | var ns2 = cls.createNamespace('2');
17 |
18 | // emulate an incoming data emitter
19 | setTimeout(function() {
20 | ee.emit('data', 'hi');
21 | }, 100);
22 |
23 | t.doesNotThrow(function() {
24 | ns1.bindEmitter(ee);
25 | });
26 | t.doesNotThrow(function() {
27 | ns2.bindEmitter(ee);
28 | });
29 |
30 | ns1.run(function() {
31 | ns2.run(function() {
32 | ns1.set('name', 'tom1');
33 | ns2.set('name', 'paul2');
34 |
35 | // Should do nothing as it wraps emitters only once
36 | //t.doesNotThrow(function () { ns1.bindEmitter(ee); });
37 | //t.doesNotThrow(function () { ns2.bindEmitter(ee); });
38 |
39 | ns1.run(function() {
40 | process.nextTick(function() {
41 | t.equal(ns1.get('name'), 'tom1', "ns1 value correct");
42 | //process._rawDebug(util.inspect(ns1), true);
43 |
44 | t.equal(ns2.get('name'), 'paul2', "ns2 value correct");
45 | //process._rawDebug(util.inspect(ns2), true);
46 |
47 | ns1.set('name', 'bob');
48 | ns2.set('name', 'alice');
49 |
50 | ee.on('data', function() {
51 | t.equal(ns1.get('name'), 'bob', "ns1 value bound onto emitter");
52 | t.equal(ns2.get('name'), 'alice', "ns2 value bound onto emitter");
53 | });
54 | });
55 | });
56 | });
57 | });
58 | });
59 | });
60 |
--------------------------------------------------------------------------------
/test/tap/bind-emitter.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const test = require('tap').test;
4 | const EventEmitter = require('events').EventEmitter;
5 | const cls = require('../../index.js');
6 |
7 | test("event emitters bound to CLS context", function (t) {
8 | t.plan(13);
9 |
10 | t.test("handler registered in context, emit out of context", function (t) {
11 | t.plan(1);
12 |
13 | var n = cls.createNamespace('in')
14 | , ee = new EventEmitter()
15 | ;
16 |
17 | n.run(function () {
18 | n.set('value', 'hello');
19 | n.bindEmitter(ee);
20 | ee.on('event', function () {
21 | t.equal(n.get('value'), 'hello', "value still set in EE.");
22 | cls.destroyNamespace('in');
23 | });
24 | });
25 |
26 | ee.emit('event');
27 | });
28 |
29 | t.test("once handler registered in context", function (t) {
30 | t.plan(1);
31 |
32 | var n = cls.createNamespace('inOnce')
33 | , ee = new EventEmitter()
34 | ;
35 |
36 | n.run(function () {
37 | n.set('value', 'hello');
38 | n.bindEmitter(ee);
39 | ee.once('event', function () {
40 | t.equal(n.get('value'), 'hello', "value still set in EE.");
41 | cls.destroyNamespace('inOnce');
42 | });
43 | });
44 |
45 | ee.emit('event');
46 | });
47 |
48 | t.test("handler registered out of context, emit in context", function (t) {
49 | t.plan(1);
50 |
51 | var n = cls.createNamespace('out')
52 | , ee = new EventEmitter()
53 | ;
54 |
55 | ee.on('event', function () {
56 | t.equal(n.get('value'), 'hello', "value still set in EE.");
57 | cls.destroyNamespace('out');
58 | });
59 |
60 | n.run(function () {
61 | n.set('value', 'hello');
62 | n.bindEmitter(ee);
63 |
64 | ee.emit('event');
65 | });
66 | });
67 |
68 | t.test("once handler registered out of context", function (t) {
69 | t.plan(1);
70 |
71 | var n = cls.createNamespace('outOnce')
72 | , ee = new EventEmitter()
73 | ;
74 |
75 | ee.once('event', function () {
76 | t.equal(n.get('value'), 'hello', "value still set in EE.");
77 | cls.destroyNamespace('outOnce');
78 | });
79 |
80 | n.run(function () {
81 | n.set('value', 'hello');
82 | n.bindEmitter(ee);
83 |
84 | ee.emit('event');
85 | });
86 | });
87 |
88 | t.test("handler registered out of context, emit out of context", function (t) {
89 | t.plan(1);
90 |
91 | var n = cls.createNamespace('out')
92 | , ee = new EventEmitter()
93 | ;
94 |
95 | ee.on('event', function () {
96 | t.equal(n.get('value'), undefined, "no context.");
97 | cls.destroyNamespace('out');
98 | });
99 |
100 | n.run(function () {
101 | n.set('value', 'hello');
102 | n.bindEmitter(ee);
103 | });
104 |
105 | ee.emit('event');
106 | });
107 |
108 | t.test("once handler registered out of context on Readable", function (t) {
109 | var Readable = require('stream').Readable;
110 |
111 | if (Readable) {
112 | t.plan(12);
113 |
114 | var n = cls.createNamespace('outOnceReadable')
115 | , re = new Readable()
116 | ;
117 |
118 | re._read = function () {};
119 |
120 | t.ok(n.name, "namespace has a name");
121 | t.equal(n.name, 'outOnceReadable', "namespace has a name");
122 |
123 | re.once('data', function (data) {
124 | t.equal(n.get('value'), 'hello', "value still set in EE");
125 | t.equal(data, 'blah', "emit still works");
126 | cls.destroyNamespace('outOnceReadable');
127 | });
128 |
129 | n.run(function () {
130 | n.set('value', 'hello');
131 |
132 | t.notOk(re.emit.__wrapped, "emit is not wrapped");
133 | t.notOk(re.on.__wrapped, "on is not wrapped");
134 | t.notOk(re.addListener.__wrapped, "addListener is not wrapped");
135 |
136 | n.bindEmitter(re);
137 |
138 | t.ok(re.emit.__wrapped, "emit is wrapped");
139 | t.ok(re.on.__wrapped, "on is wrapped");
140 | t.ok(re.addListener.__wrapped, "addListener is wrapped");
141 |
142 | t.equal(typeof re._events.data, 'function', 'only the one data listener');
143 | t.notOk(re._events.data['context@outOnceReadable'], "context isn't on listener");
144 |
145 | re.emit('data', 'blah');
146 | });
147 | }
148 | else {
149 | t.comment("this test requires node 0.10+");
150 | t.end();
151 | }
152 | });
153 |
154 | t.test("emitter with newListener that removes handler", function (t) {
155 | t.plan(3);
156 |
157 | var n = cls.createNamespace('newListener')
158 | , ee = new EventEmitter()
159 | ;
160 |
161 | // add monkeypatching to ee
162 | n.bindEmitter(ee);
163 |
164 | function listen() {
165 | ee.on('data', function (chunk) {
166 | t.equal(chunk, 'chunk', 'listener still works');
167 | });
168 | }
169 |
170 | ee.on('newListener', function handler(event) {
171 | if (event !== 'data') return;
172 |
173 | this.removeListener('newListener', handler);
174 | t.notOk(this.listeners('newListener').length, 'newListener was removed');
175 | process.nextTick(listen);
176 | });
177 |
178 | ee.on('drain', function (chunk) {
179 | process.nextTick(function () {
180 | ee.emit('data', chunk);
181 | });
182 | });
183 |
184 | ee.on('data', function (chunk) {
185 | t.equal(chunk, 'chunk', 'got data event');
186 | cls.destroyNamespace('newListener');
187 | });
188 |
189 | ee.emit('drain', 'chunk');
190 | });
191 |
192 | t.test("handler registered in context on Readable", function (t) {
193 | var Readable = require('stream').Readable;
194 |
195 | if (Readable) {
196 | t.plan(12);
197 |
198 | var n = cls.createNamespace('outOnReadable')
199 | , re = new Readable()
200 | ;
201 |
202 | re._read = function () {};
203 |
204 | t.ok(n.name, "namespace has a name");
205 | t.equal(n.name, 'outOnReadable', "namespace has a name");
206 |
207 | n.run(function () {
208 | n.set('value', 'hello');
209 |
210 | n.bindEmitter(re);
211 |
212 | t.ok(re.emit.__wrapped, "emit is wrapped");
213 | t.ok(re.on.__wrapped, "on is wrapped");
214 | t.ok(re.addListener.__wrapped, "addListener is wrapped");
215 |
216 | re.on('data', function (data) {
217 | t.equal(n.get('value'), 'hello', "value still set in EE");
218 | t.equal(data, 'blah', "emit still works");
219 | cls.destroyNamespace('outOnReadable');
220 | });
221 | });
222 |
223 | t.ok(re.emit.__wrapped, "emit is still wrapped");
224 | t.ok(re.on.__wrapped, "on is still wrapped");
225 | t.ok(re.addListener.__wrapped, "addListener is still wrapped");
226 |
227 | t.equal(typeof re._events.data, 'function', 'only the one data listener');
228 | t.ok(re._events.data['cls@contexts']['context@outOnReadable'],
229 | "context is bound to listener");
230 |
231 | re.emit('data', 'blah');
232 | }
233 | else {
234 | t.comment("this test requires node 0.10+");
235 | t.end();
236 | }
237 | });
238 |
239 | t.test("handler added but used entirely out of context", function (t) {
240 | t.plan(2);
241 |
242 | var n = cls.createNamespace('none')
243 | , ee = new EventEmitter()
244 | ;
245 |
246 | n.run(function () {
247 | n.set('value', 'hello');
248 | n.bindEmitter(ee);
249 | });
250 |
251 | ee.on('event', function () {
252 | t.ok(n, "n is set");
253 | t.notOk(n.get('value'), "value shouldn't be visible");
254 | cls.destroyNamespace('none');
255 | });
256 |
257 | ee.emit('event');
258 | });
259 |
260 | t.test("handler added but no listeners registered", function (t) {
261 | t.plan(3);
262 |
263 | var http = require('http')
264 | , n = cls.createNamespace('no_listener')
265 | ;
266 |
267 | // only fails on Node < 0.10
268 | var server = http.createServer(function (req, res) {
269 | n.bindEmitter(req);
270 |
271 | t.doesNotThrow(function () {
272 | req.emit('event');
273 | });
274 |
275 | res.writeHead(200, {"Content-Length" : 4});
276 | res.end('WORD');
277 | });
278 | server.listen(8080);
279 |
280 | http.get('http://localhost:8080/', function (res) {
281 | t.equal(res.statusCode, 200, "request came back OK");
282 |
283 | res.setEncoding('ascii');
284 | res.on('data', function (body) {
285 | t.equal(body, 'WORD', 'body should match WORD');
286 |
287 | server.close();
288 | cls.destroyNamespace('no_listener');
289 | });
290 | });
291 | });
292 |
293 | t.test("listener with parameters added but not bound to context", function (t) {
294 | t.plan(2);
295 |
296 | var ee = new EventEmitter()
297 | , n = cls.createNamespace('param_list')
298 | ;
299 |
300 | function sent(value) {
301 | t.equal(value, 3, "sent value is correct");
302 | cls.destroyNamespace('param_list');
303 | }
304 |
305 | ee.on('send', sent);
306 | n.bindEmitter(ee);
307 | t.doesNotThrow(function () {
308 | ee.emit('send', 3);
309 | });
310 | });
311 |
312 | t.test("listener that throws doesn't leave removeListener wrapped", function (t) {
313 | t.plan(4);
314 |
315 | var ee = new EventEmitter()
316 | , n = cls.createNamespace('kaboom')
317 | ;
318 |
319 | n.bindEmitter(ee);
320 |
321 | function kaboom() {
322 | throw new Error('whoops');
323 | }
324 |
325 | n.run(function () {
326 | ee.on('bad', kaboom);
327 |
328 | t.throws(function () { ee.emit('bad'); });
329 | t.equal(typeof ee.removeListener, 'function', 'removeListener is still there');
330 | t.notOk(ee.removeListener.__wrapped, "removeListener got unwrapped");
331 | t.equal(ee._events.bad, kaboom, "listener isn't still bound");
332 | cls.destroyNamespace('kaboom');
333 | });
334 | });
335 |
336 | t.test("emitter bound to multiple namespaces handles them correctly", function (t) {
337 | t.plan(8);
338 |
339 | var ee = new EventEmitter()
340 | , ns1 = cls.createNamespace('1')
341 | , ns2 = cls.createNamespace('2')
342 | ;
343 |
344 | // emulate an incoming data emitter
345 | setTimeout(function () {
346 | ee.emit('data', 'hi');
347 | }, 10);
348 |
349 | t.doesNotThrow(function () { ns1.bindEmitter(ee); });
350 | t.doesNotThrow(function () { ns2.bindEmitter(ee); });
351 |
352 | ns1.run(function () {
353 | ns2.run(function () {
354 | ns1.set('name', 'tom1');
355 | ns2.set('name', 'tom2');
356 |
357 | t.doesNotThrow(function () { ns1.bindEmitter(ee); });
358 | t.doesNotThrow(function () { ns2.bindEmitter(ee); });
359 |
360 | ns1.run(function () {
361 | process.nextTick(function () {
362 | t.equal(ns1.get('name'), 'tom1', "ns1 value correct");
363 | t.equal(ns2.get('name'), 'tom2', "ns2 value correct");
364 |
365 | ns1.set('name', 'bob');
366 | ns2.set('name', 'alice');
367 |
368 | ee.on('data', function () {
369 | t.equal(ns1.get('name'), 'bob', "ns1 value bound onto emitter");
370 | t.equal(ns2.get('name'), 'alice', "ns2 value bound onto emitter");
371 | });
372 | });
373 | });
374 | });
375 | });
376 | });
377 | });
378 |
--------------------------------------------------------------------------------
/test/tap/bind.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // stdlib
4 | var tap = require('tap');
5 | var test = tap.test;
6 | var EventEmitter = require('events').EventEmitter;
7 |
8 | // module under test
9 | var context = require('../../index.js');
10 |
11 | // multiple contexts in use
12 | var tracer = context.createNamespace('tracer');
13 |
14 | function Trace(harvester) {
15 | this.harvester = harvester;
16 | }
17 |
18 | Trace.prototype.runHandler = function (callback) {
19 | var wrapped = tracer.bind(function () {
20 | callback();
21 | this.harvester.emit('finished', tracer.get('transaction'));
22 | }.bind(this));
23 | wrapped();
24 | };
25 |
26 |
27 | test("simple tracer built on contexts", function (t) {
28 | t.plan(6);
29 |
30 | var harvester = new EventEmitter();
31 | var trace = new Trace(harvester);
32 |
33 | harvester.on('finished', function (transaction) {
34 | t.ok(transaction, "transaction should have been passed in");
35 | t.equal(transaction.status, 'ok', "transaction should have finished OK");
36 | t.equal(Object.keys(process.namespaces).length, 1, "Should only have one namespace.");
37 | });
38 |
39 | trace.runHandler(function inScope() {
40 | t.ok(tracer.active, "tracer should have an active context");
41 | tracer.set('transaction', {status : 'ok'});
42 | t.ok(tracer.get('transaction'), "can retrieve newly-set value");
43 | t.equal(tracer.get('transaction').status, 'ok', "value should be correct");
44 | });
45 | });
46 |
--------------------------------------------------------------------------------
/test/tap/crypto.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const tap = require('tap');
4 | const test = tap.test;
5 | const createNamespace = require('../../index.js').createNamespace;
6 |
7 | let crypto;
8 | try { crypto = require('crypto'); }
9 | catch (err) {}
10 |
11 | if (crypto) {
12 | test('continuation-local state with crypto.randomBytes', function (t) {
13 | t.plan(1);
14 |
15 | const namespace = createNamespace('namespace');
16 | namespace.run(function () {
17 | namespace.set('test', 0xabad1dea);
18 |
19 | t.test("deflate", function (t) {
20 | namespace.run(function () {
21 | namespace.set('test', 42);
22 | crypto.randomBytes(100, function (err) {
23 | if (err) throw err;
24 | t.equal(namespace.get('test'), 42, "mutated state was preserved");
25 | t.end();
26 | });
27 | });
28 | });
29 | });
30 | });
31 |
32 | test("continuation-local state with crypto.pseudoRandomBytes", function (t) {
33 | t.plan(1);
34 |
35 | const namespace = createNamespace('namespace');
36 | namespace.run(function () {
37 | namespace.set('test', 0xabad1dea);
38 |
39 | t.test("deflate", function (t) {
40 | namespace.run(function () {
41 | namespace.set('test', 42);
42 | crypto.pseudoRandomBytes(100, function (err) {
43 | if (err) throw err;
44 | t.equal(namespace.get('test'), 42, "mutated state was preserved");
45 | t.end();
46 | });
47 | });
48 | });
49 | });
50 | });
51 |
52 | test("continuation-local state with crypto.pbkdf2", function (t) {
53 | t.plan(1);
54 |
55 | const namespace = createNamespace('namespace');
56 | namespace.run(function () {
57 | namespace.set('test', 0xabad1dea);
58 |
59 | t.test("deflate", function (t) {
60 | namespace.run(function () {
61 | namespace.set('test', 42);
62 | crypto.pbkdf2("s3cr3tz", "451243", 10, 40, 'sha512', function (err) {
63 | if (err) throw err;
64 | t.equal(namespace.get('test'), 42, "mutated state was preserved");
65 | t.end();
66 | });
67 | });
68 | });
69 | });
70 | });
71 | }
72 |
--------------------------------------------------------------------------------
/test/tap/dns.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var dns = require('dns')
4 | , tap = require('tap')
5 | , test = tap.test
6 | , createNamespace = require('./../../index.js').createNamespace
7 | ;
8 |
9 | test("continuation-local state with MakeCallback and DNS module", function (t) {
10 | t.plan(11);
11 |
12 | var namespace = createNamespace('dns');
13 | namespace.run(function () {
14 | namespace.set('test', 0xabad1dea);
15 |
16 | t.test("dns.lookup", function (t) {
17 | namespace.run(function () {
18 | namespace.set('test', 808);
19 | t.equal(namespace.get('test'), 808, "state has been mutated");
20 |
21 | dns.lookup('www.newrelic.com', 4, function (err, addresses) {
22 | t.notOk(err, "lookup succeeded");
23 | t.ok(addresses.length > 0, "some results were found");
24 |
25 | t.equal(namespace.get('test'), 808,
26 | "mutated state has persisted to dns.lookup's callback");
27 |
28 | t.end();
29 | });
30 | });
31 | });
32 |
33 | t.test("dns.resolve", function (t) {
34 | namespace.run(function () {
35 | namespace.set('test', 909);
36 | t.equal(namespace.get('test'), 909, "state has been mutated");
37 |
38 | dns.resolve('newrelic.com', 'NS', function (err, addresses) {
39 | t.notOk(err, "lookup succeeded");
40 | t.ok(addresses.length > 0, "some results were found");
41 |
42 | t.equal(namespace.get('test'), 909,
43 | "mutated state has persisted to dns.resolve's callback");
44 |
45 | t.end();
46 | });
47 | });
48 | });
49 |
50 | t.test("dns.resolve4", function (t) {
51 | namespace.run(function () {
52 | namespace.set('test', 303);
53 | t.equal(namespace.get('test'), 303, "state has been mutated");
54 |
55 | dns.resolve4('www.newrelic.com', function (err, addresses) {
56 | t.notOk(err, "lookup succeeded");
57 | t.ok(addresses.length > 0, "some results were found");
58 |
59 | t.equal(namespace.get('test'), 303,
60 | "mutated state has persisted to dns.resolve4's callback");
61 |
62 | t.end();
63 | });
64 | });
65 | });
66 |
67 | t.test("dns.resolve6", function (t) {
68 | namespace.run(function () {
69 | namespace.set('test', 101);
70 | t.equal(namespace.get('test'), 101, "state has been mutated");
71 |
72 | dns.resolve6('google.com', function (err, addresses) {
73 | t.notOk(err, "lookup succeeded");
74 | t.ok(addresses.length > 0, "some results were found");
75 |
76 | t.equal(namespace.get('test'), 101,
77 | "mutated state has persisted to dns.resolve6's callback");
78 |
79 | t.end();
80 | });
81 | });
82 | });
83 |
84 | t.test("dns.resolveCname", function (t) {
85 | namespace.run(function () {
86 | namespace.set('test', 212);
87 | t.equal(namespace.get('test'), 212, "state has been mutated");
88 |
89 | dns.resolveCname('developers.google.com', function (err, addresses) {
90 | t.notOk(err, "lookup succeeded");
91 | t.ok(addresses.length > 0, "some results were found");
92 |
93 | t.equal(namespace.get('test'), 212,
94 | "mutated state has persisted to dns.resolveCname's callback");
95 |
96 | t.end();
97 | });
98 | });
99 | });
100 |
101 | t.test("dns.resolveMx", function (t) {
102 | namespace.run(function () {
103 | namespace.set('test', 707);
104 | t.equal(namespace.get('test'), 707, "state has been mutated");
105 |
106 | dns.resolveMx('newrelic.com', function (err, addresses) {
107 | t.notOk(err, "lookup succeeded");
108 | t.ok(addresses.length > 0, "some results were found");
109 |
110 | t.equal(namespace.get('test'), 707,
111 | "mutated state has persisted to dns.resolveMx's callback");
112 |
113 | t.end();
114 | });
115 | });
116 | });
117 |
118 | t.test("dns.resolveNs", function (t) {
119 | namespace.run(function () {
120 | namespace.set('test', 717);
121 | t.equal(namespace.get('test'), 717, "state has been mutated");
122 |
123 | dns.resolveNs('newrelic.com', function (err, addresses) {
124 | t.notOk(err, "lookup succeeded");
125 | t.ok(addresses.length > 0, "some results were found");
126 |
127 | t.equal(namespace.get('test'), 717,
128 | "mutated state has persisted to dns.resolveNs's callback");
129 |
130 | t.end();
131 | });
132 | });
133 | });
134 |
135 | t.test("dns.resolveTxt", function (t) {
136 | namespace.run(function () {
137 | namespace.set('test', 2020);
138 | t.equal(namespace.get('test'), 2020, "state has been mutated");
139 |
140 | dns.resolveTxt('newrelic.com', function (err, addresses) {
141 | t.notOk(err, "lookup succeeded");
142 | t.ok(addresses.length > 0, "some results were found");
143 |
144 | t.equal(namespace.get('test'), 2020,
145 | "mutated state has persisted to dns.resolveTxt's callback");
146 |
147 | t.end();
148 | });
149 | });
150 | });
151 |
152 | t.test("dns.resolveSrv", function (t) {
153 | namespace.run(function () {
154 | namespace.set('test', 9000);
155 | t.equal(namespace.get('test'), 9000, "state has been mutated");
156 |
157 | dns.resolveSrv('_xmpp-server._tcp.google.com', function (err, addresses) {
158 | t.notOk(err, "lookup succeeded");
159 | t.ok(addresses.length > 0, "some results were found");
160 |
161 | t.equal(namespace.get('test'), 9000,
162 | "mutated state has persisted to dns.resolveSrv's callback");
163 |
164 | t.end();
165 | });
166 | });
167 | });
168 |
169 | t.test("dns.resolveNaptr", function (t) {
170 | // dns.resolveNaptr only in Node > 0.9.x
171 | if (!dns.resolveNaptr) return t.end();
172 |
173 | namespace.run(function () {
174 | namespace.set('test', 'Polysix');
175 | t.equal(namespace.get('test'), 'Polysix', "state has been mutated");
176 |
177 | dns.resolveNaptr('columbia.edu', function (err, addresses) {
178 | t.notOk(err, "lookup succeeded");
179 | t.ok(addresses.length > 0, "some results were found");
180 |
181 | t.equal(namespace.get('test'), 'Polysix',
182 | "mutated state has persisted to dns.resolveNaptr's callback");
183 |
184 | t.end();
185 | });
186 | });
187 | });
188 |
189 | t.test("dns.reverse", function (t) {
190 | namespace.run(function () {
191 | namespace.set('test', 1000);
192 | t.equal(namespace.get('test'), 1000, "state has been mutated");
193 |
194 | dns.reverse('204.93.223.144', function (err, addresses) {
195 | t.notOk(err, "lookup succeeded");
196 | t.ok(addresses.length > 0, "some results were found");
197 |
198 | t.equal(namespace.get('test'), 1000,
199 | "mutated state has persisted to dns.reverse's callback");
200 |
201 | t.end();
202 | });
203 | });
204 | });
205 | });
206 | });
207 |
--------------------------------------------------------------------------------
/test/tap/error-handling.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var test = require('tap').test
4 | , cls = require('../../index.js')
5 | , domain = require('domain')
6 | ;
7 |
8 | test("continuation-local storage glue with a throw in the continuation chain",
9 | function (t) {
10 | var namespace = cls.createNamespace('test');
11 | namespace.run(function () {
12 | var d = domain.create();
13 | namespace.set('outer', true);
14 |
15 | d.on('error', function (blerg) {
16 | t.equal(blerg.message, "explicitly nonlocal exit", "got the expected exception");
17 | t.ok(namespace.get('outer'), "outer context is still active");
18 | t.notOk(namespace.get('inner'), "inner context should have been exited by throw");
19 | t.equal(namespace._set.length, 1, "should be back to outer state");
20 |
21 | cls.destroyNamespace('test');
22 | t.end();
23 | });
24 |
25 | // tap is only trying to help
26 | process.nextTick(d.bind(function () {
27 | t.ok(namespace.get('outer'), "outer mutation worked");
28 | t.notOk(namespace.get('inner'), "inner mutation hasn't happened yet");
29 |
30 | namespace.run(function () {
31 | namespace.set('inner', true);
32 | throw new Error("explicitly nonlocal exit");
33 | });
34 | }));
35 | });
36 | });
37 |
38 | test("synchronous throw attaches the context", function (t) {
39 | t.plan(3);
40 |
41 | var namespace = cls.createNamespace('cls@synchronous');
42 | namespace.run(function () {
43 | namespace.set('value', 'transaction clear');
44 | try {
45 | namespace.run(function () {
46 | namespace.set('value', 'transaction set');
47 | throw new Error('cls@synchronous explosion');
48 | });
49 | }
50 | catch (e) {
51 | t.ok(namespace.fromException(e), "context was attached to error");
52 | t.equal(namespace.fromException(e)['value'], 'transaction set',
53 | "found the inner value");
54 | }
55 |
56 | t.equal(namespace.get('value'), 'transaction clear', "everything was reset");
57 | });
58 |
59 | cls.destroyNamespace('cls@synchronous');
60 | });
61 |
62 | test("synchronous throw checks if error exists", function (t) {
63 | t.plan(2);
64 |
65 | var namespace = cls.createNamespace('cls@synchronous-null-error');
66 | namespace.run(function () {
67 | namespace.set('value', 'transaction clear');
68 | try {
69 | namespace.run(function () {
70 | namespace.set('value', 'transaction set');
71 | throw null;
72 | });
73 | }
74 | catch (e) {
75 | // as we had a null error, cls couldn't set the new inner value
76 | t.equal(namespace.get('value'), 'transaction clear', 'from outer value');
77 | }
78 |
79 | t.equal(namespace.get('value'), 'transaction clear', "everything was reset");
80 | });
81 |
82 | cls.destroyNamespace('cls@synchronous-null-error');
83 | });
84 |
85 | test("throw in process.nextTick attaches the context", function (t) {
86 | t.plan(3);
87 |
88 | var namespace = cls.createNamespace('cls@nexttick2');
89 |
90 | var d = domain.create();
91 | d.once('error', function (e) {
92 | t.ok(namespace.fromException(e), "context was attached to error");
93 | t.equal(namespace.fromException(e)['value'], 'transaction set',
94 | "found the inner value");
95 |
96 | cls.destroyNamespace('cls@nexttick2');
97 | });
98 |
99 | namespace.run(function () {
100 | namespace.set('value', 'transaction clear');
101 |
102 | // tap is only trying to help
103 | process.nextTick(d.bind(function () {
104 | namespace.run(function () {
105 | namespace.set('value', 'transaction set');
106 | throw new Error("cls@nexttick2 explosion");
107 | });
108 | }));
109 |
110 | t.equal(namespace.get('value'), 'transaction clear', "everything was reset");
111 | });
112 | });
113 |
114 | test("throw in setTimeout attaches the context", function (t) {
115 | t.plan(3);
116 |
117 | var namespace = cls.createNamespace('cls@nexttick3');
118 | var d = domain.create();
119 |
120 | d.once('error', function (e) {
121 | t.ok(namespace.fromException(e), "context was attached to error");
122 | t.equal(namespace.fromException(e)['value'], 'transaction set',
123 | "found the inner value");
124 |
125 | cls.destroyNamespace('cls@nexttick3');
126 | });
127 |
128 | namespace.run(function () {
129 | namespace.set('value', 'transaction clear');
130 |
131 | // tap is only trying to help
132 | setTimeout(d.bind(function () {
133 | namespace.run(function () {
134 | namespace.set('value', 'transaction set');
135 | throw new Error("cls@nexttick3 explosion");
136 | });
137 | }));
138 |
139 | t.equal(namespace.get('value'), 'transaction clear', "everything was reset");
140 | });
141 | });
142 |
--------------------------------------------------------------------------------
/test/tap/interleave-contexts.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var cls = require('../../index.js')
4 | , test = require('tap').test
5 | ;
6 |
7 | function cleanNamespace(name){
8 | if (cls.getNamespace(name)) cls.destroyNamespace(name);
9 | return cls.createNamespace(name);
10 | }
11 |
12 | test("interleaved contexts", function (t) {
13 | t.plan(3);
14 |
15 | t.test("interleaving with run", function (t) {
16 | t.plan(2);
17 |
18 | var ns = cleanNamespace('test');
19 |
20 | var ctx = ns.createContext();
21 |
22 | ns.enter(ctx);
23 | ns.run(function () {
24 | t.equal(ns._set.length, 2, "2 contexts in the active set");
25 | t.doesNotThrow(function () { ns.exit(ctx); });
26 | });
27 | });
28 |
29 | t.test("entering and exiting staggered", function (t) {
30 | t.plan(4);
31 |
32 | var ns = cleanNamespace('test');
33 |
34 | var ctx1 = ns.createContext();
35 | var ctx2 = ns.createContext();
36 |
37 | t.doesNotThrow(function () { ns.enter(ctx1); });
38 | t.doesNotThrow(function () { ns.enter(ctx2); });
39 |
40 | t.doesNotThrow(function () { ns.exit(ctx1); });
41 | t.doesNotThrow(function () { ns.exit(ctx2); });
42 | });
43 |
44 | t.test("creating, entering and exiting staggered", function (t) {
45 | t.plan(4);
46 |
47 | var ns = cleanNamespace('test');
48 |
49 | var ctx1 = ns.createContext();
50 | t.doesNotThrow(function () { ns.enter(ctx1); });
51 |
52 | var ctx2 = ns.createContext();
53 | t.doesNotThrow(function () { ns.enter(ctx2); });
54 |
55 | t.doesNotThrow(function () { ns.exit(ctx1); });
56 | t.doesNotThrow(function () { ns.exit(ctx2); });
57 | });
58 | });
59 |
--------------------------------------------------------------------------------
/test/tap/namespaces-multiple-values.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const test = require('tap').test;
4 | const util = require('util');
5 |
6 | const cls = require('./../../index.js');
7 |
8 | test("multiple namespaces handles them correctly", function(t) {
9 | t.plan(4);
10 |
11 | var ns1 = cls.createNamespace('ONE');
12 | var ns2 = cls.createNamespace('TWO');
13 |
14 | ns1.run(function() {
15 | ns2.run(function() {
16 | ns1.set('name', 'tom1');
17 | ns2.set('name', 'paul2');
18 |
19 | setTimeout(function() {
20 |
21 | ns1.run(function() {
22 |
23 | process.nextTick(function() {
24 | t.equal(ns1.get('name'), 'tom1', "ns1 value correct");
25 | //process._rawDebug(util.inspect(ns1), true);
26 |
27 | t.equal(ns2.get('name'), 'paul2', "ns2 value correct");
28 | //process._rawDebug(util.inspect(ns2), true);
29 |
30 | ns1.set('name', 'bob');
31 | ns2.set('name', 'alice');
32 |
33 | setTimeout(function() {
34 | t.equal(ns1.get('name'), 'bob', "ns1 value bound onto emitter");
35 | t.equal(ns2.get('name'), 'alice', "ns2 value bound onto emitter");
36 | });
37 |
38 | });
39 |
40 | });
41 |
42 | });
43 |
44 | });
45 | });
46 | });
47 |
48 |
--------------------------------------------------------------------------------
/test/tap/namespaces.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var tap = require('tap');
4 | var test = tap.test;
5 |
6 | var context = require('../../index.js');
7 |
8 | test("namespace management", function (t) {
9 | t.plan(8);
10 |
11 | t.throws(function () { context.createNamespace(); }, "name is required");
12 |
13 | var namespace = context.createNamespace('test');
14 | t.ok(namespace, "namespace is returned upon creation");
15 |
16 | t.equal(context.getNamespace('test'), namespace, "namespace lookup works");
17 |
18 | t.doesNotThrow(function () { context.reset(); }, "allows resetting namespaces");
19 |
20 | t.equal(Object.keys(process.namespaces).length, 0, "namespaces have been reset");
21 |
22 | namespace = context.createNamespace('another');
23 | t.ok(process.namespaces.another, "namespace is available from global");
24 |
25 | t.doesNotThrow(function () { context.destroyNamespace('another'); },
26 | "destroying works");
27 |
28 | t.notOk(process.namespaces.another, "namespace has been removed");
29 | });
30 |
--------------------------------------------------------------------------------
/test/tap/nesting.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var tap = require('tap');
4 | var test = tap.test;
5 |
6 | var cls = require('../../index.js');
7 |
8 | test('nested contexts on a single namespace', function (t) {
9 | t.plan(7);
10 |
11 | var namespace = cls.createNamespace('namespace');
12 | namespace.run(function () {
13 | namespace.set('value', 1);
14 |
15 | t.equal(namespace.get('value'), 1,
16 | 'namespaces have associated data even without contexts.');
17 |
18 | namespace.run(function () {
19 | t.equal(namespace.get('value'), 1, 'lookup will check enclosing context');
20 | namespace.set('value', 2);
21 | t.equal(namespace.get('value'), 2, 'setting works on top-level context');
22 |
23 | namespace.run(function () {
24 | t.equal(namespace.get('value'), 2, 'lookup will check enclosing context');
25 | namespace.set('value', 3);
26 | t.equal(namespace.get('value'), 3, 'setting works on nested context');
27 | });
28 |
29 | t.equal(namespace.get('value'), 2,
30 | 'should revert to value set in top-level context');
31 | });
32 |
33 | t.equal(namespace.get('value'), 1, 'namespace retains its outermost value.');
34 | });
35 | });
36 |
37 | test('the example from the docs', function (t) {
38 | var ns = cls.createNamespace('writer');
39 | ns.run(function () {
40 | ns.set('value', 0);
41 |
42 | t.equal(ns.get('value'), 0, 'outer hasn\'t been entered yet');
43 |
44 | function requestHandler() {
45 | ns.run(function (outer) {
46 | t.equal(ns.active, outer, 'writer.active == outer');
47 |
48 | ns.set('value', 1);
49 | t.equal(ns.get('value'), 1, 'value is 1');
50 | t.equal(outer.value, 1, 'outer is active');
51 |
52 | process.nextTick(function () {
53 | t.equal(ns.active, outer, 'writer.active == outer');
54 | t.equal(ns.get('value'), 1, 'inner has been entered');
55 | ns.run(function (inner) {
56 | t.equal(ns.active, inner, 'writer.active == inner');
57 |
58 | ns.set('value', 2);
59 | t.equal(outer.value, 1, 'outer is unchanged');
60 | t.equal(inner.value, 2, 'inner is active');
61 | t.equal(ns.get('value'), 2, 'writer.active == inner');
62 | });
63 | });
64 | });
65 |
66 | setTimeout(function () {
67 | t.equal(ns.get('value'), 0, 'writer.active == global');
68 | t.end();
69 | }, 100);
70 | }
71 |
72 | requestHandler();
73 | });
74 | });
75 |
--------------------------------------------------------------------------------
/test/tap/net-events.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var net = require('net');
4 | var test = require('tap').test;
5 | var createNamespace = require('../../index').createNamespace;
6 |
7 | test('continuation-local state with net connection', function(t) {
8 | t.plan(4);
9 |
10 | var namespace = createNamespace('net');
11 | namespace.run(function() {
12 | namespace.set('test', 'originalValue');
13 |
14 | var server;
15 | namespace.run(function() {
16 | namespace.set('test', 'newContextValue');
17 |
18 | server = net.createServer(function(socket) {
19 | t.equal(namespace.get('test'), 'newContextValue', 'state has been mutated');
20 | socket.on('data', function() {
21 | t.equal(namespace.get('test'), 'newContextValue', 'state is still preserved');
22 | server.close();
23 | socket.end('GoodBye');
24 | });
25 | });
26 | server.listen(function() {
27 | var address = server.address();
28 | namespace.run(function() {
29 | namespace.set('test', 'MONKEY');
30 | var client = net.connect(address.port, function() {
31 | t.equal(namespace.get('test'), 'MONKEY', 'state preserved for client connection');
32 | client.write('Hello');
33 | client.on('data', function() {
34 | t.equal(namespace.get('test'), 'MONKEY', 'state preserved for client data');
35 | t.end();
36 | });
37 | });
38 | });
39 | });
40 | });
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/test/tap/promises.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var tap = require('tap')
4 | , test = tap.test
5 | , createNamespace = require('../../index.js').createNamespace
6 | ;
7 |
8 | test("continuation-local state with promises", function (t) {
9 | t.plan(4);
10 |
11 | var namespace = createNamespace('namespace');
12 | namespace.run(function () {
13 | namespace.set('test', 0xabad1dea);
14 |
15 | t.test("chained promises", function (t) {
16 | if (!global.Promise) return t.end();
17 |
18 | namespace.run(function () {
19 | namespace.set('test', 31337);
20 | t.equal(namespace.get('test'), 31337, "state has been mutated");
21 |
22 | Promise.resolve()
23 | .then(function () {
24 | t.equal(namespace.get('test'), 31337,
25 | "mutated state has persisted to first continuation");
26 | })
27 | .then(function () {
28 | t.equal(namespace.get('test'), 31337,
29 | "mutated state has persisted to second continuation");
30 | })
31 | .then(function () {
32 | t.equal(namespace.get('test'), 31337,
33 | "mutated state has persisted to third continuation");
34 | t.end();
35 | });
36 | });
37 | });
38 |
39 | t.test("chained unwrapped promises", function (t) {
40 | if (!global.Promise) return t.end();
41 |
42 | namespace.run(function () {
43 | namespace.set('test', 999);
44 | t.equal(namespace.get('test'), 999, "state has been mutated");
45 |
46 | Promise.resolve()
47 | .then(function () {
48 | t.equal(namespace.get('test'), 999,
49 | "mutated state has persisted to first continuation");
50 | return Promise.resolve();
51 | })
52 | .then(function () {
53 | t.equal(namespace.get('test'), 999,
54 | "mutated state has persisted to second continuation");
55 | return Promise.resolve();
56 | })
57 | .then(function () {
58 | t.equal(namespace.get('test'), 999,
59 | "mutated state has persisted to third continuation");
60 | t.end();
61 | });
62 | });
63 | });
64 |
65 | t.test("nested promises", function (t) {
66 | if (!global.Promise) return t.end();
67 |
68 | namespace.run(function () {
69 | namespace.set('test', 54321);
70 | t.equal(namespace.get('test'), 54321, "state has been mutated");
71 |
72 | Promise.resolve()
73 | .then(function () {
74 | t.equal(namespace.get('test'), 54321,
75 | "mutated state has persisted to first continuation");
76 |
77 | Promise.resolve()
78 | .then(function () {
79 | t.equal(namespace.get('test'), 54321,
80 | "mutated state has persisted to second continuation");
81 |
82 | Promise.resolve()
83 | .then(function () {
84 | t.equal(namespace.get('test'), 54321,
85 | "mutated state has persisted to third continuation");
86 | t.end();
87 | });
88 | });
89 | });
90 | });
91 | });
92 |
93 | t.test("forked continuations", function (t) {
94 | if (!global.Promise) return t.end();
95 |
96 | namespace.run(function () {
97 | namespace.set('test', 10101);
98 | t.equal(namespace.get('test'), 10101, "state has been mutated");
99 |
100 | var promise = Promise.resolve();
101 |
102 | promise
103 | .then(function () {
104 | t.equal(namespace.get('test'), 10101,
105 | "mutated state has persisted to first continuation");
106 | });
107 | promise
108 | .then(function () {
109 | t.equal(namespace.get('test'), 10101,
110 | "mutated state has persisted to second continuation");
111 | });
112 | promise
113 | .then(function () {
114 | t.equal(namespace.get('test'), 10101,
115 | "mutated state has persisted to third continuation");
116 | t.end();
117 | });
118 | });
119 | });
120 | });
121 | });
122 |
--------------------------------------------------------------------------------
/test/tap/proper-exit.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var tap = require('tap');
3 | var test = tap.test;
4 | var util = require('util');
5 |
6 | test('proper exit on uncaughtException', {skip: true}, function(t) {
7 | process.on('uncaughtException', function(err) {
8 | if (err.message === 'oops') {
9 | //console.log("ok got expected message: %s", err.message);
10 | t.pass(util.format("ok got expected message: %s", err.message));
11 | }
12 | else {
13 | throw err;
14 | }
15 | });
16 |
17 | var cls = require('../../index.js');
18 | var ns = cls.createNamespace('x');
19 | ns.run(function() {
20 | throw new Error('oops');
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/test/tap/run-and-return.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // stdlib
4 | var tap = require('tap');
5 | var test = tap.test;
6 | var EventEmitter = require('events').EventEmitter;
7 |
8 | // module under test
9 | var context = require('../../index.js');
10 |
11 | // multiple contexts in use
12 | var tracer = context.createNamespace('tracer');
13 |
14 |
15 | test("simple tracer built on contexts", function (t) {
16 | t.plan(7);
17 |
18 | var harvester = new EventEmitter();
19 |
20 | harvester.on('finished', function (transaction) {
21 | t.ok(transaction, "transaction should have been passed in");
22 | t.equal(transaction.status, 'ok', "transaction should have finished OK");
23 | t.equal(Object.keys(process.namespaces).length, 1, "Should only have one namespace.");
24 | });
25 |
26 | var returnValue = {};
27 |
28 | var returnedValue = tracer.runAndReturn(function(context) {
29 | t.ok(tracer.active, "tracer should have an active context");
30 | tracer.set('transaction', {status : 'ok'});
31 | t.ok(tracer.get('transaction'), "can retrieve newly-set value");
32 | t.equal(tracer.get('transaction').status, 'ok', "value should be correct");
33 |
34 | harvester.emit('finished', context.transaction);
35 |
36 | return returnValue;
37 | });
38 |
39 | t.equal(returnedValue, returnValue, "method should pass through return value of function run in scope");
40 | });
41 |
--------------------------------------------------------------------------------
/test/tap/simple.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // stdlib
4 | const tap = require('tap');
5 | const test = tap.test;
6 | const EventEmitter = require('events').EventEmitter;
7 |
8 | // module under test
9 | const context = require('../../index.js');
10 |
11 | // multiple contexts in use
12 | const tracer = context.createNamespace('tracer');
13 |
14 | function Trace(harvester) {
15 | this.harvester = harvester;
16 | }
17 |
18 | Trace.prototype.runHandler = function (handler) {
19 | let trace = tracer.run(handler);
20 | this.harvester.emit('finished', trace.transaction);
21 | };
22 |
23 |
24 | test("simple tracer built on contexts", function (t) {
25 | t.plan(6);
26 |
27 | let harvester = new EventEmitter();
28 | let trace = new Trace(harvester);
29 |
30 | harvester.on('finished', function (transaction) {
31 | t.ok(transaction, "transaction should have been passed in");
32 | t.equal(transaction.status, 'ok', "transaction should have finished OK");
33 | t.equal(Object.keys(process.namespaces).length, 1, "Should only have one namespace.");
34 | });
35 |
36 | trace.runHandler(function inScope() {
37 | t.ok(tracer.active, "tracer should have an active context");
38 | tracer.set('transaction', {status : 'ok'});
39 | t.ok(tracer.get('transaction'), "can retrieve newly-set value");
40 | t.equal(tracer.get('transaction').status, 'ok', "value should be correct");
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/test/tap/timers.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const tap = require('tap');
4 | const test = tap.test;
5 | const createNamespace = require('../../index.js').createNamespace;
6 |
7 | test("continuation-local state with timers", function (t) {
8 | t.plan(4);
9 |
10 | var namespace = createNamespace('namespace');
11 | namespace.run(function () {
12 | namespace.set('test', 0xabad1dea);
13 |
14 | t.test("process.nextTick", function (t) {
15 | namespace.run(function () {
16 | namespace.set('test', 31337);
17 | t.equal(namespace.get('test'), 31337, "state has been mutated");
18 |
19 | process.nextTick(function () {
20 | t.equal(namespace.get('test'), 31337,
21 | "mutated state has persisted to process.nextTick's callback");
22 |
23 | t.end();
24 | });
25 | });
26 | });
27 |
28 | t.test("setImmediate", function (t) {
29 | // setImmediate only in Node > 0.9.x
30 | if (!global.setImmediate) return t.end();
31 |
32 | namespace.run(function () {
33 | namespace.set('test', 999);
34 | t.equal(namespace.get('test'), 999, "state has been mutated");
35 |
36 | setImmediate(function () {
37 | t.equal(namespace.get('test'), 999,
38 | "mutated state has persisted to setImmediate's callback");
39 |
40 | t.end();
41 | });
42 | });
43 | });
44 |
45 | t.test("setTimeout", function (t) {
46 | namespace.run(function () {
47 | namespace.set('test', 54321);
48 | t.equal(namespace.get('test'), 54321, "state has been mutated");
49 |
50 | setTimeout(function () {
51 | t.equal(namespace.get('test'), 54321,
52 | "mutated state has persisted to setTimeout's callback");
53 |
54 | t.end();
55 | });
56 | });
57 | });
58 |
59 | t.test("setInterval", function (t) {
60 | namespace.run(function () {
61 | namespace.set('test', 10101);
62 | t.equal(namespace.get('test'), 10101,
63 | "continuation-local state has been mutated");
64 |
65 | var ref = setInterval(function () {
66 | t.equal(namespace.get('test'), 10101,
67 | "mutated state has persisted to setInterval's callback");
68 |
69 | clearInterval(ref);
70 | t.end();
71 | }, 20);
72 | });
73 | });
74 | });
75 | });
76 |
--------------------------------------------------------------------------------
/test/tap/tracer-scenarios.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const EventEmitter = require('events').EventEmitter;
4 | const assert = require('assert');
5 | const test = require('tap').test;
6 | const cls = require('../../index.js');
7 |
8 | let nextID = 1;
9 | function fresh(name) {
10 | assert.ok(!cls.getNamespace(name), "namespace " + name + " already exists");
11 | return cls.createNamespace(name);
12 | }
13 |
14 | function destroy(name) {
15 | return function destroyer(t) {
16 | cls.destroyNamespace(name);
17 | assert.ok(!cls.getNamespace(name), "namespace '" + name + "' should no longer exist");
18 | t.end();
19 | };
20 | }
21 |
22 | function runInTransaction(name, fn) {
23 | let namespace = cls.getNamespace(name);
24 | assert(namespace, "namespaces " + name + " doesn't exist");
25 |
26 | let context = namespace.createContext();
27 | context.transaction = ++nextID;
28 | process.nextTick(namespace.bind(fn, context));
29 | }
30 |
31 | test("asynchronous state propagation", function (t) {
32 | t.plan(24);
33 |
34 | t.test("a. async transaction with setTimeout", function (t) {
35 | t.plan(2);
36 |
37 | let namespace = fresh('a', this);
38 |
39 | function handler() {
40 | t.ok(namespace.get('transaction'), "transaction should be visible");
41 | }
42 |
43 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
44 | runInTransaction('a', function () { setTimeout(handler, 100); });
45 | });
46 |
47 | t.test("a. cleanup", destroy('a'));
48 |
49 | t.test("b. async transaction with setInterval", function (t) {
50 | t.plan(4);
51 |
52 | let namespace = fresh('b', this)
53 | , count = 0
54 | , handle
55 | ;
56 |
57 | function handler() {
58 | count += 1;
59 | if (count > 2) clearInterval(handle);
60 | t.ok(namespace.get('transaction'), "transaction should be visible");
61 | }
62 |
63 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
64 | runInTransaction('b', function () { handle = setInterval(handler, 50); });
65 | });
66 |
67 | t.test("b. cleanup", destroy('b'));
68 |
69 | t.test("c. async transaction with process.nextTick", function (t) {
70 | t.plan(2);
71 |
72 | let namespace = fresh('c', this);
73 |
74 | function handler() {
75 | t.ok(namespace.get('transaction'), "transaction should be visible");
76 | }
77 |
78 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
79 | runInTransaction('c', function () { process.nextTick(handler); });
80 | });
81 |
82 | t.test("c. cleanup", destroy('c'));
83 |
84 | t.test("d. async transaction with EventEmitter.emit", function (t) {
85 | t.plan(2);
86 |
87 | let namespace = fresh('d', this);
88 | let ee = new EventEmitter();
89 |
90 | function handler() {
91 | t.ok(namespace.get('transaction'), "transaction should be visible");
92 | }
93 |
94 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
95 | runInTransaction('d', function () {
96 | ee.on('transaction', handler);
97 | ee.emit('transaction');
98 | });
99 | });
100 |
101 | t.test("d. cleanup", destroy('d'));
102 |
103 | t.test("e. two overlapping async transactions with setTimeout", function (t) {
104 | t.plan(6);
105 |
106 | let namespace = fresh('e', this)
107 | , first
108 | , second
109 | ;
110 |
111 | function handler(id) {
112 | t.ok(namespace.get('transaction'), "transaction should be visible");
113 | t.equal(namespace.get('transaction'), id, "transaction matches");
114 | }
115 |
116 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
117 | runInTransaction('e', function () {
118 | first = namespace.get('transaction');
119 | setTimeout(handler.bind(null, first), 100);
120 | });
121 |
122 | setTimeout(function () {
123 | runInTransaction('e', function () {
124 | second = namespace.get('transaction');
125 | t.notEqual(first, second, "different transaction IDs");
126 | setTimeout(handler.bind(null, second), 100);
127 | });
128 | }, 25);
129 | });
130 |
131 | t.test("e. cleanup", destroy('e'));
132 |
133 | t.test("f. two overlapping async transactions with setInterval", function (t) {
134 | t.plan(15);
135 |
136 | let namespace = fresh('f', this);
137 |
138 | function runInterval() {
139 | let count = 0;
140 | let handle;
141 | let id;
142 |
143 | function handler() {
144 | count += 1;
145 | if (count > 2) clearInterval(handle);
146 | t.ok(namespace.get('transaction'), "transaction should be visible");
147 | t.equal(id, namespace.get('transaction'), "transaction ID should be immutable");
148 | }
149 |
150 | function run() {
151 | t.ok(namespace.get('transaction'), "transaction should have been created");
152 | id = namespace.get('transaction');
153 | handle = setInterval(handler, 50);
154 | }
155 |
156 | runInTransaction('f', run);
157 | }
158 |
159 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
160 | runInterval(); runInterval();
161 | });
162 |
163 | t.test("f. cleanup", destroy('f'));
164 |
165 | t.test("g. two overlapping async transactions with process.nextTick", function (t) {
166 | t.plan(6);
167 |
168 | let namespace = fresh('g', this);
169 | let first;
170 | let second;
171 |
172 | function handler(id) {
173 | var transaction = namespace.get('transaction');
174 | t.ok(transaction, "transaction should be visible");
175 | t.equal(transaction, id, "transaction matches");
176 | }
177 |
178 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
179 | runInTransaction('g', function () {
180 | first = namespace.get('transaction');
181 | process.nextTick(handler.bind(null, first));
182 | });
183 |
184 | process.nextTick(function () {
185 | runInTransaction('g', function () {
186 | second = namespace.get('transaction');
187 | t.notEqual(first, second, "different transaction IDs");
188 | process.nextTick(handler.bind(null, second));
189 | });
190 | });
191 | });
192 |
193 | t.test("g. cleanup", destroy('g'));
194 |
195 | t.test("h. two overlapping async runs with EventEmitter.prototype.emit", function (t) {
196 | t.plan(3);
197 |
198 | let namespace = fresh('h', this);
199 | let ee = new EventEmitter();
200 |
201 | function handler() {
202 | t.ok(namespace.get('transaction'), "transaction should be visible");
203 | }
204 |
205 | function lifecycle() {
206 | ee.once('transaction', process.nextTick.bind(process, handler));
207 | ee.emit('transaction');
208 | }
209 |
210 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
211 | runInTransaction('h', lifecycle);
212 | runInTransaction('h', lifecycle);
213 | });
214 |
215 | t.test("h. cleanup", destroy('h'));
216 |
217 | t.test("i. async transaction with an async sub-call with setTimeout", function (t) {
218 | t.plan(5);
219 |
220 | var namespace = fresh('i', this);
221 |
222 | function inner(callback) {
223 | setTimeout(function () {
224 | t.ok(namespace.get('transaction'), "transaction should (yep) still be visible");
225 | callback();
226 | }, 50);
227 | }
228 |
229 | function outer() {
230 | t.ok(namespace.get('transaction'), "transaction should be visible");
231 | setTimeout(function () {
232 | t.ok(namespace.get('transaction'), "transaction should still be visible");
233 | inner(function () {
234 | t.ok(namespace.get('transaction'), "transaction should even still be visible");
235 | });
236 | }, 50);
237 | }
238 |
239 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
240 | runInTransaction('i', setTimeout.bind(null, outer, 50));
241 | });
242 |
243 | t.test("i. cleanup", destroy('i'));
244 |
245 | t.test("j. async transaction with an async sub-call with setInterval", function (t) {
246 | t.plan(5);
247 |
248 | let namespace = fresh('j', this);
249 | let outerHandle;
250 | let innerHandle;
251 |
252 | function inner(callback) {
253 | innerHandle = setInterval(function () {
254 | clearInterval(innerHandle);
255 | t.ok(namespace.get('transaction'), "transaction should (yep) still be visible");
256 | callback();
257 | }, 50);
258 | }
259 |
260 | function outer() {
261 | t.ok(namespace.get('transaction'), "transaction should be visible");
262 | outerHandle = setInterval(function () {
263 | clearInterval(outerHandle);
264 | t.ok(namespace.get('transaction'), "transaction should still be visible");
265 | inner(function () {
266 | t.ok(namespace.get('transaction'), "transaction should even still be visible");
267 | });
268 | }, 50);
269 | }
270 |
271 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
272 | runInTransaction('j', outer);
273 | });
274 |
275 | t.test("j. cleanup", destroy('j'));
276 |
277 | t.test("k. async transaction with an async call with process.nextTick", function (t) {
278 | t.plan(5);
279 |
280 | let namespace = fresh('k', this);
281 |
282 | function inner(callback) {
283 | process.nextTick(function () {
284 | t.ok(namespace.get('transaction'), "transaction should (yep) still be visible");
285 | callback();
286 | });
287 | }
288 |
289 | function outer() {
290 | t.ok(namespace.get('transaction'), "transaction should be visible");
291 | process.nextTick(function () {
292 | t.ok(namespace.get('transaction'), "transaction should still be visible");
293 | inner(function () {
294 | t.ok(namespace.get('transaction'), "transaction should even still be visible");
295 | });
296 | });
297 | }
298 |
299 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
300 | runInTransaction('k', function () { process.nextTick(outer); });
301 | });
302 |
303 | t.test("k. cleanup", destroy('k'));
304 |
305 | t.test("l. async transaction with an async call with EventEmitter.emit", function (t) {
306 | t.plan(4);
307 |
308 | let namespace = fresh('l', this);
309 | let outer = new EventEmitter();
310 | let inner = new EventEmitter();
311 |
312 | inner.on('pong', function (callback) {
313 | t.ok(namespace.get('transaction'), "transaction should still be visible");
314 | callback();
315 | });
316 |
317 | function outerCallback() {
318 | t.ok(namespace.get('transaction'), "transaction should even still be visible");
319 | }
320 |
321 | outer.on('ping', function () {
322 | t.ok(namespace.get('transaction'), "transaction should be visible");
323 | inner.emit('pong', outerCallback);
324 | });
325 |
326 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible");
327 | runInTransaction('l', outer.emit.bind(outer, 'ping'));
328 | });
329 |
330 | t.test("l. cleanup", destroy('l'));
331 | });
332 |
--------------------------------------------------------------------------------
/test/tap/zlib.tap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const tap = require('tap');
4 | const test = tap.test;
5 | const createNamespace = require('../../index.js').createNamespace;
6 |
7 | const zlib = require('zlib');
8 |
9 | test("continuation-local state with zlib", function (t) {
10 | t.plan(1);
11 |
12 | var namespace = createNamespace('namespace');
13 | namespace.run(function () {
14 | namespace.set('test', 0xabad1dea);
15 |
16 | t.test("deflate", function (t) {
17 | namespace.run(function () {
18 | namespace.set('test', 42);
19 | zlib.deflate(new Buffer("Goodbye World"), function (err) {
20 | if (err) throw err;
21 | t.equal(namespace.get('test'), 42, "mutated state was preserved");
22 | t.end();
23 | });
24 | });
25 | });
26 | });
27 | });
28 |
--------------------------------------------------------------------------------