skywalking-backend-js-netease
Version:
The NodeJS agent for Apache SkyWalking
185 lines • 6.16 kB
JavaScript
;
/*!
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const SwPlugin_1 = require("../../core/SwPlugin");
const ContextManager_1 = tslib_1.__importDefault(require("../context/ContextManager"));
const ARGS_REG = /^args\[(\d)\]$/;
/**
* Typescript Method Decorators for tracing customize method.
*
* @param config config of this
* @returns Typescript Method Decorators
*/
function default_1(config) {
return function (target, propertyKey, descriptor) {
const _originalMethod = descriptor.value;
descriptor.value = function (...args) {
var _a;
// create local span
config = checkArgs(config, (_a = target === null || target === void 0 ? void 0 : target.constructor) === null || _a === void 0 ? void 0 : _a.name, propertyKey);
let operationName = config.operationName;
if (config.operationNameSuffix) {
const ret = getSuffix.apply(this, [config.operationNameSuffix, args]);
operationName = ret ? operationName + '/' + ret : operationName;
}
const span = ContextManager_1.default.current.newLocalSpan(operationName);
if (config.tags) {
config.tags.forEach((val, key) => {
const ret = calculate.apply(this, [val, args]);
if (ret) {
span.tag({ key: key, overridable: true, val: ret });
}
});
}
if (config.logs) {
config.logs.forEach((val, key) => {
const ret = calculate.apply(this, [val, args]);
if (ret) {
span.log(key, ret);
}
});
}
span.start();
// check args, if cb?
const hasCB = typeof arguments[arguments.length - 1] === 'function';
try {
if (hasCB) {
const wrappedCallback = SwPlugin_1.wrapCallback(span, arguments[arguments.length - 1], 0);
arguments[arguments.length - 1] = wrappedCallback;
}
// execute origin
let ret = _originalMethod.apply(this, args);
if (!hasCB) {
if (ret && typeof ret.then === 'function') {
ret = SwPlugin_1.wrapPromise(span, ret);
}
else { // sync function, no cb/promise.
span.stop();
return ret;
}
}
span.async();
return ret;
}
catch (err) {
span.error(err);
span.stop();
throw err;
}
};
return descriptor;
};
}
exports.default = default_1;
;
function checkArgs(config, className, methodName) {
let conf = {};
if (config) {
if (typeof config === 'string') {
conf.operationName = config;
}
else {
conf.operationName = config.operationName || (className + '/' + methodName);
conf.tags = config.tags;
conf.logs = config.logs;
conf.operationNameSuffix = config.operationNameSuffix;
}
}
else {
conf.operationName = className + '/' + methodName;
}
return conf;
}
function getSuffix(operationNameSuffix, args) {
return operationNameSuffix.map(x => calculate(x, args)).filter(x => x !== '').join('/');
}
function calculate(exp, args) {
if (!exp || args.length === 0) {
return '';
}
let index = -1;
let exps = exp.split('.');
if (exps.length >= 1) {
const ret = ARGS_REG.exec(exps[0]);
index = +((ret === null || ret === void 0 ? void 0 : ret[1]) || '-1');
if (index < 0 || isNaN(index) || index > args.length) {
return '';
}
}
try {
// args[i].$method().$field, eval args[i]
let [ok, ret] = getVal(args[index]);
if (!ok) {
return ret;
}
// [$method(), $field]
for (let i = 1; i < exps.length; i += 1) {
[ok, ret] = calculateExp(exps[i], ret);
if (!ok) {
return ret;
}
}
return ret;
}
catch (e) {
// ignore
}
return '';
}
function getVal(ret) {
switch (typeof ret) {
case 'undefined':
return [false, ''];
case 'string':
case 'boolean':
case 'number':
case 'bigint':
return [false, `${ret}`];
case 'object':
if (!ret) {
return [false, ''];
}
}
return [true, ret];
}
function calculateExp(exp, obj) {
if (!exp || !obj) {
return [false, ''];
}
try {
const isFunc = exp.endsWith('()');
if (isFunc) {
exp = exp.substr(0, exp.length - 2);
}
const ff = obj[exp];
if (isFunc && ff && typeof ff === 'function') {
return getVal(ff.apply(obj));
}
if (ff) {
return getVal(ff);
}
}
catch (e) {
// ignore
}
return [false, ''];
}
//# sourceMappingURL=Decorator.js.map