-
Notifications
You must be signed in to change notification settings - Fork 227
/
ioredis.js
94 lines (81 loc) · 2.73 KB
/
ioredis.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*
* Copyright Elasticsearch B.V. and other contributors where applicable.
* Licensed under the BSD 2-Clause License; you may not use this file except in
* compliance with the BSD 2-Clause License.
*/
'use strict';
// Instrumentation of the 'ioredis' package:
// https://github.com/luin/ioredis
// https://github.com/luin/ioredis/blob/master/API.md
const semver = require('semver');
const constants = require('../../constants');
const { getDBDestination } = require('../context');
const shimmer = require('../shimmer');
const TYPE = 'db';
const SUBTYPE = 'redis';
const ACTION = 'query';
const hasIoredisSpanSym = Symbol('ElasticAPMHasIoredisSpan');
module.exports = function (ioredis, agent, { version, enabled }) {
if (!enabled) {
return ioredis;
}
if (!semver.satisfies(version, '>=2.0.0 <6.0.0')) {
agent.logger.debug(
'ioredis version %s not supported - aborting...',
version,
);
return ioredis;
}
const ins = agent._instrumentation;
agent.logger.debug('shimming ioredis.prototype.sendCommand');
shimmer.wrap(ioredis.prototype, 'sendCommand', wrapSendCommand);
return ioredis;
function wrapSendCommand(origSendCommand) {
return function wrappedSendCommand(command) {
if (!command || !command.name || !command.promise) {
// Doesn't look like an ioredis.Command, skip instrumenting.
return origSendCommand.apply(this, arguments);
}
if (command[hasIoredisSpanSym]) {
// Avoid double-instrumenting a command when ioredis *re*-calls
// sendCommand for queued commands when "ready".
return origSendCommand.apply(this, arguments);
}
agent.logger.debug(
{ command: command.name },
'intercepted call to ioredis.prototype.sendCommand',
);
const span = ins.createSpan(
command.name.toUpperCase(),
TYPE,
SUBTYPE,
ACTION,
{ exitSpan: true },
);
if (!span) {
return origSendCommand.apply(this, arguments);
}
command[hasIoredisSpanSym] = true;
const options = this.options || {}; // `this` is the `Redis` client.
span._setDestinationContext(getDBDestination(options.host, options.port));
span.setDbContext({ type: 'redis' });
const spanRunContext = ins.currRunContext().enterSpan(span);
command.promise.then(
() => {
span.end();
},
ins.bindFunctionToRunContext(spanRunContext, (err) => {
span._setOutcomeFromErrorCapture(constants.OUTCOME_FAILURE);
agent.captureError(err, { skipOutcome: true });
span.end();
}),
);
return ins.withRunContext(
spanRunContext,
origSendCommand,
this,
...arguments,
);
};
}
};