Skip to content

Commit 95f3198

Browse files
author
Stephen Belanger
committed
lib: add tracing channel to diagnostics_channel
1 parent 7e09c6c commit 95f3198

5 files changed

+290
-0
lines changed

lib/diagnostics_channel.js

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,134 @@ function hasSubscribers(name) {
136136
return channel.hasSubscribers;
137137
}
138138

139+
class TracingChannel {
140+
constructor(name) {
141+
this.name = name;
142+
this.channels = {
143+
start: channel(`${name}.start`),
144+
end: channel(`${name}.end`),
145+
asyncEnd: channel(`${name}.asyncEnd`),
146+
error: channel(`${name}.error`)
147+
};
148+
}
149+
150+
get hasSubscribers() {
151+
const { channels } = this;
152+
for (const key in channels) {
153+
if (channels[key].hasSubscribers) return true;
154+
}
155+
return false;
156+
}
157+
158+
subscribe(handlers) {
159+
let subscribed = true;
160+
for (const key in handlers) {
161+
if (!subscribe(`${this.name}.${key}`, handlers[key])) {
162+
subscribed = false;
163+
}
164+
}
165+
return subscribed;
166+
}
167+
168+
unsubscribe(handlers) {
169+
let unsubscribed = true;
170+
for (const key in handlers) {
171+
if (!unsubscribe(`${this.name}.${key}`, handlers[key])) {
172+
unsubscribed = false;
173+
}
174+
}
175+
return unsubscribed;
176+
}
177+
178+
traceSync(fn, ctx = {}, thisArg, ...args) {
179+
const { start, end, error } = this.channels;
180+
start.publish(ctx);
181+
try {
182+
const result = fn.apply(thisArg, args);
183+
ctx.result = result;
184+
return result;
185+
} catch (err) {
186+
ctx.error = err;
187+
error.publish(ctx);
188+
throw err;
189+
} finally {
190+
end.publish(ctx);
191+
}
192+
}
193+
194+
tracePromise(fn, ctx = {}, thisArg, ...args) {
195+
const { asyncEnd, start, end, error } = this.channels;
196+
start.publish(ctx);
197+
198+
const reject = (err) => {
199+
ctx.error = err;
200+
error.publish(ctx);
201+
asyncEnd.publish(ctx);
202+
throw err;
203+
};
204+
205+
const resolve = (result) => {
206+
ctx.result = result;
207+
asyncEnd.publish(ctx);
208+
return result;
209+
};
210+
211+
try {
212+
return fn.apply(thisArg, args).then(resolve, reject);
213+
} catch (err) {
214+
ctx.error = err;
215+
error.publish(ctx);
216+
throw err;
217+
} finally {
218+
end.publish(ctx);
219+
}
220+
}
221+
222+
traceCallback(fn, position = 0, ctx = {}, thisArg, ...args) {
223+
const { start, end, asyncEnd, error } = this.channels;
224+
start.publish(ctx);
225+
226+
function wrap(fn) {
227+
return function wrappedCallback (err, res) {
228+
if (err) {
229+
ctx.error = err;
230+
error.publish(ctx);
231+
} else {
232+
ctx.result = res;
233+
}
234+
235+
asyncEnd.publish(ctx);
236+
if (fn) {
237+
return fn.apply(this, arguments);
238+
}
239+
}
240+
}
241+
242+
if (position >= 0) {
243+
args.splice(position, 1, wrap(args.at(position)));
244+
}
245+
246+
try {
247+
return fn.apply(thisArg, args);
248+
} catch (err) {
249+
ctx.error = err;
250+
error.publish(ctx);
251+
throw err;
252+
} finally {
253+
end.publish(ctx);
254+
}
255+
}
256+
}
257+
258+
function tracingChannel(name) {
259+
return new TracingChannel(name);
260+
}
261+
139262
module.exports = {
140263
channel,
141264
hasSubscribers,
142265
subscribe,
266+
tracingChannel,
143267
unsubscribe,
144268
Channel
145269
};
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const dc = require('diagnostics_channel');
5+
const assert = require('assert');
6+
7+
const channel = dc.tracingChannel('test');
8+
9+
const expectedError = new Error('test');
10+
const input = { foo: 'bar' };
11+
const thisArg = { baz: 'buz' };
12+
13+
function check(found) {
14+
assert.deepStrictEqual(found, input);
15+
}
16+
17+
const handlers = {
18+
start: common.mustCall(check, 2),
19+
end: common.mustCall(check, 2),
20+
asyncEnd: common.mustCall(check, 2),
21+
error: common.mustCall((found) => {
22+
check(found);
23+
assert.deepStrictEqual(found.error, expectedError);
24+
}, 2)
25+
};
26+
27+
channel.subscribe(handlers);
28+
29+
channel.traceCallback(function (cb, err) {
30+
assert.deepStrictEqual(this, thisArg);
31+
setImmediate(cb, err);
32+
}, 0, input, thisArg, common.mustCall((err, res) => {
33+
assert.strictEqual(err, expectedError);
34+
assert.deepStrictEqual(res, undefined);
35+
}), expectedError);
36+
37+
channel.tracePromise(function (value) {
38+
assert.deepStrictEqual(this, thisArg);
39+
return Promise.reject(value);
40+
}, input, thisArg, expectedError).then(
41+
common.mustNotCall(),
42+
common.mustCall(value => {
43+
assert.deepStrictEqual(value, expectedError);
44+
})
45+
);
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const dc = require('diagnostics_channel');
5+
const assert = require('assert');
6+
7+
const channel = dc.tracingChannel('test');
8+
9+
const expectedResult = { foo: 'bar' };
10+
const input = { foo: 'bar' };
11+
const thisArg = { baz: 'buz' };
12+
13+
function check(found) {
14+
assert.deepStrictEqual(found, input);
15+
}
16+
17+
const handlers = {
18+
start: common.mustCall(check, 2),
19+
end: common.mustCall(check, 2),
20+
asyncEnd: common.mustCall((found) => {
21+
check(found);
22+
assert.strictEqual(found.error, undefined);
23+
assert.deepStrictEqual(found.result, expectedResult);
24+
}, 2),
25+
error: common.mustNotCall()
26+
};
27+
28+
channel.subscribe(handlers);
29+
30+
channel.traceCallback(function (cb, err, res) {
31+
assert.deepStrictEqual(this, thisArg);
32+
setImmediate(cb, err, res);
33+
}, 0, input, thisArg, common.mustCall((err, res) => {
34+
assert.strictEqual(err, null);
35+
assert.deepStrictEqual(res, expectedResult);
36+
}), null, expectedResult);
37+
38+
channel.tracePromise(function (value) {
39+
assert.deepStrictEqual(this, thisArg);
40+
return Promise.resolve(value);
41+
}, input, thisArg, expectedResult).then(
42+
common.mustCall(value => {
43+
assert.deepStrictEqual(value, expectedResult);
44+
}),
45+
common.mustNotCall()
46+
);
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const dc = require('diagnostics_channel');
5+
const assert = require('assert');
6+
7+
const channel = dc.tracingChannel('test');
8+
9+
const expectedError = new Error('test');
10+
const input = { foo: 'bar' };
11+
const thisArg = { baz: 'buz' };
12+
13+
function check(found) {
14+
assert.deepStrictEqual(found, input);
15+
}
16+
17+
const handlers = {
18+
start: common.mustCall(check),
19+
end: common.mustCall(check),
20+
asyncEnd: common.mustNotCall(),
21+
error: common.mustCall((found) => {
22+
check(found);
23+
assert.deepStrictEqual(found.error, expectedError);
24+
})
25+
};
26+
27+
channel.subscribe(handlers);
28+
try {
29+
channel.traceSync(function (err) {
30+
assert.deepStrictEqual(this, thisArg);
31+
assert.strictEqual(err, expectedError);
32+
throw err;
33+
}, input, thisArg, expectedError);
34+
35+
throw new Error('It should not reach this error');
36+
} catch (error) {
37+
assert.deepStrictEqual(error, expectedError);
38+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const dc = require('diagnostics_channel');
5+
const assert = require('assert');
6+
7+
const channel = dc.tracingChannel('test');
8+
9+
const expectedResult = { foo: 'bar' };
10+
const input = { foo: 'bar' };
11+
12+
function check(found) {
13+
assert.deepStrictEqual(found, input);
14+
}
15+
16+
const handlers = {
17+
start: common.mustCall(check),
18+
end: common.mustCall((found) => {
19+
check(found);
20+
assert.deepStrictEqual(found.result, expectedResult);
21+
}),
22+
asyncEnd: common.mustNotCall(),
23+
error: common.mustNotCall()
24+
};
25+
26+
assert.strictEqual(channel.hasSubscribers, false);
27+
channel.subscribe(handlers);
28+
assert.strictEqual(channel.hasSubscribers, true);
29+
channel.traceSync(() => {
30+
return expectedResult;
31+
}, input);
32+
33+
channel.unsubscribe(handlers);
34+
assert.strictEqual(channel.hasSubscribers, false);
35+
channel.traceSync(() => {
36+
return expectedResult;
37+
}, input);

0 commit comments

Comments
 (0)