pinpoint-node-agent
Version:
Pinpoint node agent provided by NAVER
225 lines (185 loc) • 5.98 kB
JavaScript
/**
* Pinpoint Node.js Agent
* Copyright 2020-present NAVER Corp.
* Apache License v2.0
*/
'use strict'
const MethodDescriptor = require('../instrumentation/method-descriptor')
const MethodType = require('../constant/method-type')
const config = require('../config')
// https://v8.dev/docs/stack-trace-api#appendix%3A-stack-trace-format
class MethodDescriptorBuilder {
constructor(functionName) {
this.type = MethodType.DEFAULT
this.apiId = 0
this.parameterVariableNames = []
this.functionName = functionName
this.methodIndex = 2
this.locationFileNameIndex = 2
}
static makeRuntimeDetectionMethodDescriptorBuilder() {
return new MethodDescriptorBuilder().enableRuntimeDetection(true)
}
setType(type) {
this.type = type
return this
}
setClassName(className) {
this.className = className
return this
}
setLineNumber(lineNumber) {
this.lineNumber = lineNumber
return this
}
setLocation(location) {
this.location = location
return this
}
getFileName() {
return this.fileName
}
setFileName(fileName) {
this.fileName = fileName
return this
}
setParameterVariableNames(names) {
this.parameterVariableNames = names
return this
}
setFunctionName(functionName) {
this.functionName = functionName
return this
}
setMethodName(methodName) {
this.methodName = methodName
return this
}
setApiId(apiId) {
this.apiId = apiId
return this
}
setApiDescriptor(apiDescriptor) {
this.apiDescriptor = apiDescriptor
return this
}
getCacheId() {
if (this.apiDescriptor) {
return this.apiDescriptor
}
const cacheIds = [this.formattedStringOfCall()]
if (typeof this.fileName === 'string') {
cacheIds.push(this.fileName)
}
if (typeof this.lineNumber === 'number') {
cacheIds.push(this.lineNumber)
}
return cacheIds.join(':')
}
toggleConstruct() {
this.construct = true
delete this.async
delete this.type
return this
}
toggleAsync() {
this.async = true
delete this.construct
delete this.type
return this
}
// https://v8.dev/docs/stack-trace-api#appendix%3A-stack-trace-format
formattedStringOfCall() {
if (this.needsMethodAndFunctionName() || (this.needsFunctionNameWhenConstructOrAsync())) {
return `<anonymous>`
}
if (this.construct) {
return `new ${this.functionName}`
} else if (this.async) {
return `async ${this.functionName}`
}
const formatted = []
if (typeof this.className === 'string') {
formatted.push(`${this.className}.`)
}
if (typeof this.functionName === 'string') {
if (/<computed>$/.test(this.functionName) && typeof this.methodName === 'string') {
formatted.push(this.functionName.replace(/<computed>$/, this.methodName))
return formatted.join('')
}
formatted.push(this.functionName)
}
if (typeof this.methodName === 'string' && typeof this.functionName === 'string' && this.functionName !== this.methodName) {
formatted.push(` [as ${this.methodName}]`)
} else if (typeof this.methodName === 'string' && typeof this.functionName !== 'string') {
formatted.push(this.methodName)
}
return formatted.join('')
}
needsMethodAndFunctionName() {
return !this.functionName && !this.methodName
}
needsFunctionNameWhenConstructOrAsync() {
return (this.construct || this.async) && !this.functionName
}
isRuntimeDetection() {
return this.runtimeDetection
}
isDetectedFunctionName() {
return !this.isRuntimeDetection()
}
enableRuntimeDetection() {
this.runtimeDetection = true
return this
}
setMethodIndex(index) {
this.methodIndex = index
return this
}
setFileNameIndex(index) {
this.locationFileNameIndex = index
return this
}
shouldCallSiteFileNameAndLineNumber() {
const conf = config.getConfig()
if (!conf || !conf.traceLocationAndFileNameOfCallSite) {
return false
}
return typeof this.fileName !== 'string' && typeof this.lineNumber !== 'number'
}
makeCloneOf(functionName) {
let clone
if (functionName) {
clone = new MethodDescriptorBuilder(functionName)
} else {
clone = new MethodDescriptorBuilder(this.functionName)
}
clone.type = this.type
clone.parameterVariableNames = this.parameterVariableNames
clone.lineNumber = this.lineNumber
clone.fullName = this.fullName
clone.apiId = this.apiId
clone.apiDescriptor = this.apiDescriptor
clone.location = this.location
clone.className = this.className
return clone
}
build() {
const value = new MethodDescriptor(this.functionName)
if (this.type !== 'Function' && typeof this.methodName === 'undefined') {
value.methodName = this.functionName
} else {
value.methodName = this.methodName
}
value.type = this.type
value.parameterVariableNames = this.parameterVariableNames
value.lineNumber = this.lineNumber
value.fullName = this.fullName
value.apiId = this.apiId
value.apiDescriptor = this.apiDescriptor || this.formattedStringOfCall()
value.location = this.location
value.className = this.className
return value
}
}
module.exports = MethodDescriptorBuilder