@uyu423/pinpoint-node-agent
Version:
Pinpoint node agent provided by NAVER (Personalized version)
174 lines (139 loc) • 5.29 kB
JavaScript
/**
* Pinpoint Node.js Agent
* Copyright 2020-present NAVER Corp.
* Apache License v2.0
*/
const semver = require('semver')
const shimmer = require('shimmer')
const ServiceTypeCode = require('../../constant/service-type').ServiceTypeCode
const log = require('../../utils/logger')
// https://github.com/elastic/apm-agent-nodejs/blob/master/lib/instrumentation/modules/mysql.js
module.exports = function(agent, version, mysql) {
if (!semver.satisfies(version, '^2.0.0')) {
log.debug('mysql version %s not supported - aborting...', version)
return mysql
}
log.debug('shimming mysql.createPool')
shimmer.wrap(mysql, 'createPool', wrapCreatePool)
log.debug('shimming mysql.createPoolCluster')
shimmer.wrap(mysql, 'createPoolCluster', wrapCreatePoolCluster)
log.debug('shimming mysql.createConnection')
shimmer.wrap(mysql, 'createConnection', wrapCreateConnection)
return mysql
function wrapCreateConnection (original) {
return function wrappedCreateConnection () {
const connection = original.apply(this, arguments)
wrapQueryable(connection, 'connection', agent)
return connection
}
}
function wrapCreatePool (original) {
return function wrappedCreatePool () {
const pool = original.apply(this, arguments)
log.debug('shimming mysql pool.getConnection')
shimmer.wrap(pool, 'getConnection', wrapGetConnection)
return pool
}
}
function wrapCreatePoolCluster (original) {
return function wrappedCreatePoolCluster () {
const cluster = original.apply(this, arguments)
log.debug('shimming mysql cluster.of')
shimmer.wrap(cluster, 'of', function wrapOf (original) {
return function wrappedOf () {
const ofCluster = original.apply(this, arguments)
log.debug('shimming mysql cluster of.getConnection')
shimmer.wrap(ofCluster, 'getConnection', wrapGetConnection)
return ofCluster
}
})
return cluster
}
}
function wrapGetConnection (original) {
return function wrappedGetConnection () {
const cb = arguments[0]
if (typeof cb === 'function') {
arguments[0] = function bindFunction() {
return function wrapedCallback (err, connection) {
// eslint-disable-line handle-callback-err
if (connection) wrapQueryable(connection, 'getConnection() > connection', agent)
return cb.apply(this, arguments)
}
}
}
return original.apply(this, arguments)
}
}
function wrapQueryable (obj, objType, agent) {
log.debug('shimming mysql %s.query', objType)
shimmer.wrap(obj, 'query', wrapQuery)
function wrapQuery (original) {
return function wrappedQuery (sql, values, cb) {
let hasCallback = false
let sqlStr
const trace = agent.traceContext.currentTraceObject()
let spanEventRecorder, asyncEventRecorder, asyncTrace
if (trace) {
spanEventRecorder = trace.traceBlockBegin()
spanEventRecorder.recordServiceType(ServiceTypeCode.ASYNC_HTTP_CLIENT_INTERNAL)
spanEventRecorder.recordApiDesc('mysql.'+ String(sql).toUpperCase()+'.call' )
trace.traceBlockEnd(spanEventRecorder)
switch (typeof sql) {
case 'string':
sqlStr = sql
break
case 'object':
if (typeof sql._callback === 'function') {
sql._callback = wrapCallback(sql._callback)
}
sqlStr = sql.sql
break
case 'function':
arguments[0] = wrapCallback(sql)
break
}
const nextSpanId = IdGenerator.next
asyncTrace = trace.newAsyncTrace(spanEventRecorder)
asyncEventRecorder = asyncTrace.traceAsyncBegin()
asyncEventRecorder.recordServiceType(ServiceTypeCode.mysql)
asyncEventRecorder.recordApiDesc(`mysql.${objType}.query `)
asyncEventRecorder.recordNextSpanId(nextSpanId)
if (sqlStr) { // TODO. this point
asyncEventRecorder.recordApiArguments(EventAnnotationKey.MONGO_JSON_DATA,
convertUtils.convertStringStringValue(sqlStr), ValueType.stringStringValue)
}
if (typeof values === 'function') {
arguments[1] = wrapCallback(values)
} else if (typeof cb === 'function') {
arguments[2] = wrapCallback(cb)
}
}
const result = original.apply(this, arguments)
if (asyncTrace && result && !hasCallback) {
shimmer.wrap(result, 'emit', function (original) {
return function (event) {
switch (event) {
case 'error':
case 'end':
asyncTrace.traceAsyncEnd(asyncEventRecorder)
}
return original.apply(this, arguments)
}
})
}
return result
function wrapCallback (cb) {
hasCallback = true
return function wrappedCallback () {
if (trace) {
trace.traceAsyncEnd(asyncEventRecorder)
}
return cb.apply(this, arguments)
}
}
}
}
}
}