-
Notifications
You must be signed in to change notification settings - Fork 156
/
Copy pathpostgres_p.js
136 lines (110 loc) · 3.6 KB
/
postgres_p.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/**
* @module postgres_p
*/
var AWSXRay = require('aws-xray-sdk-core');
var events = require('events');
var SqlData = AWSXRay.database.SqlData;
var DATABASE_VERS = process.env.POSTGRES_DATABASE_VERSION;
var DRIVER_VERS = process.env.POSTGRES_DRIVER_VERSION;
var PREPARED = 'statement';
/**
* Patches the Node PostreSQL client to automatically capture query information for the segment.
* Client.query calls are automatically captured.
* In manual mode, client.query requires a sub/segment object
* as an additional argument as the last argument for the query.
* @function
* @param {pg} module - The PostgreSQL npm module.
* @returns {pg}
* @see /~https://github.com/brianc/node-postgres
*/
module.exports = function capturePostgres(pg) {
if (pg.Client.prototype.__query) {
return pg;
}
pg.Client.prototype.__query = pg.Client.prototype.query;
pg.Client.prototype.query = captureQuery;
return pg;
};
// From pg/lib/utils.js
function pgNormalizeQueryConfig(config, values, callback) {
// can take in strings or config objects
var argsObj = typeof config === 'string' ? { text: config } : config;
if (values) {
if (typeof values === 'function') {
argsObj.callback = values;
} else {
argsObj.values = values;
}
}
if (callback) {
argsObj.callback = callback;
}
return argsObj;
}
function captureQuery() {
var lastArg = arguments[arguments.length-1];
var parent = AWSXRay.resolveSegment(
(lastArg != null && lastArg.constructor &&
(lastArg.constructor.name === 'Segment' || lastArg.constructor.name === 'Subsegment'))
? lastArg
: null
);
if (!parent) {
AWSXRay.getLogger().info('Failed to capture Postgres. Cannot resolve sub/segment.');
return this.__query.apply(this, arguments);
}
var args = pgNormalizeQueryConfig.apply(this, arguments) || {};
var subsegment = parent.addNewSubsegment(this.database + '@' + this.host);
subsegment.namespace = 'remote';
if (args.callback) {
var cb = args.callback;
if (AWSXRay.isAutomaticMode()) {
args.callback = function autoContext(err, data) {
var session = AWSXRay.getNamespace();
session.run(function() {
AWSXRay.setSegment(subsegment);
cb(err, data);
});
subsegment.close(err);
};
} else {
args.callback = function(err, data) {
cb(err, data, subsegment);
subsegment.close(err);
};
}
}
var result = this.__query.call(this, args);
if (this._queryable && !this._ending) {
var query;
// To get the actual query object, we have to extract it from the
// owning connection object. The query will either be the last one in
// the queue or it will be the active query.
if (this.queryQueue.length === 0) {
query = this.activeQuery;
} else {
query = this.queryQueue[this.queryQueue.length-1];
}
if (!args.callback && query.on instanceof Function) {
query.on('end', function() {
subsegment.close();
});
var errorCapturer = function (err) {
subsegment.close(err);
};
query.on(events.errorMonitor || 'error', errorCapturer);
}
subsegment.addSqlData(createSqlData(this.connectionParameters, query));
}
return result;
}
function createSqlData(connParams, query) {
var queryType = query.name ? PREPARED : undefined;
var data = new SqlData(DATABASE_VERS, DRIVER_VERS, connParams.user,
'postgresql://' + connParams.host + ':' + connParams.port + '/' + connParams.database,
queryType);
if (process.env.AWS_XRAY_COLLECT_SQL_QUERIES) {
data.sanitized_query = query.text;
}
return data;
}