Skip to content

Commit 47c33cf

Browse files
committed
fix: 保证finalhandler时执行正常
1 parent ebdbeb3 commit 47c33cf

File tree

9 files changed

+124
-33
lines changed

9 files changed

+124
-33
lines changed

src/agent.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
const { EventEmitter } = require('events')
22

3-
class Agent extends EventEmitter {}
3+
const Transaction = require('./transaction')
4+
5+
class Agent extends EventEmitter {
6+
constructor() {
7+
super()
8+
this._transaction = new Transaction()
9+
}
10+
get transaction() {
11+
return this._transaction
12+
}
13+
}
414

515
module.exports = Agent

src/constants.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
const MODULE_TYPE = {
99
/** Web server framework module, such as Express or Koa. */
1010
WEB_FRAMEWORK: 'web-framework',
11-
PROXY: 'proxy'
11+
PROXY: 'proxy',
12+
TRANSACTION: 'transaction'
1213
}
1314

1415
exports.MODULE_TYPE = MODULE_TYPE

src/instrumentation/core/http.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
const utils = require('../../utils')
2+
3+
function wrapEmitWithTransaction(agent, emit) {
4+
const { transaction } = agent
5+
6+
return function wrappedHandler(evnt, request, response) {
7+
transaction.init()
8+
9+
function instrumentedFinish() {
10+
response.removeListener('finish', instrumentedFinish)
11+
request.removeListener('aborted', instrumentedFinish)
12+
13+
// 状态码
14+
if (response.statusCode != null) {
15+
const statusCode = String(response.statusCode)
16+
const path = transaction.path || request.path
17+
if (/^\d+$/.test(statusCode)) {
18+
const context = request.headers['x-apigateway-context']
19+
const latency = Date.now() - transaction.start
20+
const data = {
21+
latency,
22+
path,
23+
method: request.method,
24+
statusCode
25+
}
26+
agent.emit('responseFinish', context, data)
27+
}
28+
}
29+
transaction.end()
30+
}
31+
// response结束时上报状态码和耗时
32+
response.once('finish', instrumentedFinish)
33+
request.once('aborted', instrumentedFinish)
34+
35+
return emit.apply(this, arguments)
36+
}
37+
}
38+
39+
module.exports = function initialize(agent, http) {
40+
if (!http) {
41+
return false
42+
}
43+
44+
utils.wrapMethod(http.Server && http.Server.prototype, 'emit', function wrapEmit(emit) {
45+
var txStarter = wrapEmitWithTransaction(agent, emit)
46+
return function wrappedEmit(evnt) {
47+
// 针对request事件做特殊逻辑
48+
if (evnt === 'request') {
49+
return txStarter.apply(this, arguments)
50+
}
51+
return emit.apply(this, arguments)
52+
}
53+
})
54+
}

src/instrumentation/express.js

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,27 +38,9 @@ module.exports = function initialize(agent, express) {
3838
utils.wrapMethod(layer, 'handle', function(func) {
3939
const { route } = layer
4040
const { path } = route
41-
return function(request, response) {
42-
function finish() {
43-
response.removeListener('finish', finish)
44-
request.removeListener('aborted', finish)
45-
// 状态码
46-
if (response.statusCode != null) {
47-
const responseCode = String(response.statusCode)
48-
if (/^\d+$/.test(responseCode)) {
49-
const context = request.headers['x-apigateway-context']
50-
agent.emit('responseFinish', context, request.method, path, responseCode)
51-
}
52-
}
53-
}
54-
55-
// response结束时上报状态码和耗时
56-
response.once('finish', finish)
57-
request.once('aborted', finish)
58-
59-
const handle = func.apply(this, arguments)
60-
return handle
61-
}
41+
const { transaction } = agent
42+
transaction.path = path
43+
return func
6244
})
6345
}
6446
return sourceRoute

src/instrumentation/tencent-serverless-http.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
const utils = require('../utils')
2-
const { REUQEST_START_KEY } = require('../constants')
32
const report = require('../report')
43

54
module.exports = function initialize(agent, httpProxy) {
65
utils.wrapMethod(httpProxy, 'proxy', function wrapRoute(fn) {
7-
return function(server, event, context) {
8-
context[REUQEST_START_KEY] = Date.now()
6+
return function() {
7+
const { transaction } = agent
8+
transaction.init()
99
const proxy = fn.apply(this, arguments)
1010
return new Promise(function(resolve) {
11-
agent.once('responseFinish', function(ctx, method, path, responseCode) {
11+
agent.once('responseFinish', function(ctx, data) {
1212
if (ctx) {
13-
report.reportHttp(ctx, method, path, responseCode).then(
13+
report.reportHttp(ctx, data).then(
1414
function() {
1515
resolve(proxy)
1616
},

src/instrumentations.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const { MODULE_TYPE } = require('./constants')
33
module.exports = function instrumentations() {
44
return {
55
express: { type: MODULE_TYPE.WEB_FRAMEWORK },
6+
finalhandler: { type: MODULE_TYPE.WEB_FRAMEWORK },
67
'tencent-serverless-http': { type: MODULE_TYPE.PROXY }
78
}
89
}

src/report.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
const { Capi } = require('@tencent-sdk/capi')
22
const logger = require('./logger')
3-
const { REUQEST_START_KEY } = require('./constants')
43

54
// 字符串转16进制
65
function str2hex(str) {
@@ -14,7 +13,7 @@ function str2hex(str) {
1413
return arr.join('')
1514
}
1615

17-
exports.reportHttp = async function(context, method, path, statusCode) {
16+
exports.reportHttp = async function(context, { latency, method, path, statusCode }) {
1817
try {
1918
context = JSON.parse(decodeURIComponent(context))
2019
// 自定级监控上报的指标名只支持【a-zA-Z0-9_-】,所以把path进行转义上报
@@ -55,7 +54,6 @@ exports.reportHttp = async function(context, method, path, statusCode) {
5554
host: 'monitor.tencentcloudapi.com'
5655
}
5756

58-
const latency = Date.now() - context[REUQEST_START_KEY]
5957
const keyPrefix = `${method}_${path}`
6058
const Metrics = [
6159
{ MetricName: 'request', Value: 1 },

src/shimmer.js

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,25 @@ const fs = require('fs')
33
const utils = require('./utils')
44
const INSTRUMENTATIONS = require('./instrumentations')()
55

6-
function _firstPartyInstrumentation(agent, fileName, nodule) {
6+
const { MODULE_TYPE } = require('./constants')
7+
8+
const CORE_INSTRUMENTATION = {
9+
http: {
10+
type: MODULE_TYPE.TRANSACTION,
11+
file: 'http.js'
12+
},
13+
https: {
14+
type: MODULE_TYPE.TRANSACTION,
15+
file: 'http.js'
16+
}
17+
}
18+
19+
function _firstPartyInstrumentation(agent, fileName, nodule, moduleName) {
720
if (!fs.existsSync(fileName)) {
821
return
922
}
1023
try {
11-
return require(fileName)(agent, nodule)
24+
return require(fileName)(agent, nodule, moduleName)
1225
} catch (error) {
1326
agent.emit('responseFinish')
1427
}
@@ -73,6 +86,19 @@ const shimmer = {
7386
},
7487

7588
bootstrapInstrumentation: function bootstrapInstrumentation(agent) {
89+
// Instrument each of the core modules.
90+
Object.keys(CORE_INSTRUMENTATION).forEach(function forEachCore(mojule) {
91+
const core = CORE_INSTRUMENTATION[mojule]
92+
const filePath = path.join(__dirname, 'instrumentation', 'core', core.file)
93+
let uninstrumented = null
94+
95+
try {
96+
uninstrumented = require(mojule)
97+
} catch (err) {}
98+
99+
_firstPartyInstrumentation(agent, filePath, uninstrumented)
100+
})
101+
76102
// 注册所有注入模块
77103
Object.keys(INSTRUMENTATIONS).forEach(function forEachInstrumentation(moduleName) {
78104
const instrInfo = INSTRUMENTATIONS[moduleName]

src/transaction/index.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
class Transaction {
2+
get start() {
3+
return this._start
4+
}
5+
set Path(path) {
6+
this._path = path
7+
}
8+
get path() {
9+
return this._path
10+
}
11+
init() {
12+
this._start = Date.now()
13+
}
14+
end() {
15+
this._start = null
16+
this._path = null
17+
}
18+
}
19+
module.exports = Transaction

0 commit comments

Comments
 (0)