@kangc/skywalking-backend-js
Version:
The NodeJS agent for Apache SkyWalking
191 lines • 7.48 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 });
var tslib_1 = require("tslib");
var AgentConfig_1 = tslib_1.__importDefault(require("../../config/AgentConfig"));
var SpanContext_1 = tslib_1.__importDefault(require("../../trace/context/SpanContext"));
var DummyContext_1 = tslib_1.__importDefault(require("../../trace/context/DummyContext"));
var async_hooks_1 = tslib_1.__importDefault(require("async_hooks"));
var store;
if (async_hooks_1.default.AsyncLocalStorage) {
store = new async_hooks_1.default.AsyncLocalStorage();
}
else {
// Node 10 doesn't have AsyncLocalStore, so recreate it
var executionAsyncId_1 = async_hooks_1.default.executionAsyncId;
var asyncLocalStore_1 = {};
store = {
getStore: function () {
return asyncLocalStore_1[executionAsyncId_1()];
},
enterWith: function (s) {
asyncLocalStore_1[executionAsyncId_1()] = s;
},
};
async_hooks_1.default
.createHook({
init: function (asyncId, type, triggerId) {
asyncLocalStore_1[asyncId] = asyncLocalStore_1[triggerId];
},
destroy: function (asyncId) {
delete asyncLocalStore_1[asyncId];
},
})
.enable();
}
var ContextManager = /** @class */ (function () {
function ContextManager() {
this.isCold = true;
}
ContextManager.prototype.checkCold = function () {
var isCold = this.isCold;
this.isCold = false;
return isCold;
};
Object.defineProperty(ContextManager.prototype, "asyncState", {
get: function () {
var asyncState = store.getStore();
if (!asyncState) {
asyncState = { spans: [] };
store.enterWith(asyncState);
}
return asyncState;
},
enumerable: false,
configurable: true
});
Object.defineProperty(ContextManager.prototype, "currentSpan", {
get: function () {
var _a;
var spans = (_a = store.getStore()) === null || _a === void 0 ? void 0 : _a.spans;
return spans === null || spans === void 0 ? void 0 : spans[spans.length - 1];
},
enumerable: false,
configurable: true
});
Object.defineProperty(ContextManager.prototype, "hasContext", {
get: function () {
var _a;
return Boolean((_a = store.getStore()) === null || _a === void 0 ? void 0 : _a.spans.length);
},
enumerable: false,
configurable: true
});
Object.defineProperty(ContextManager.prototype, "current", {
get: function () {
var asyncState = this.asyncState;
if (asyncState.spans.length)
return asyncState.spans[asyncState.spans.length - 1].context;
if (SpanContext_1.default.nActiveSegments < AgentConfig_1.default.maxBufferSize)
return new SpanContext_1.default();
return new DummyContext_1.default();
},
enumerable: false,
configurable: true
});
Object.defineProperty(ContextManager.prototype, "spans", {
get: function () {
return this.asyncState.spans;
},
enumerable: false,
configurable: true
});
ContextManager.prototype.spansDup = function () {
var asyncState = store.getStore();
if (!asyncState) {
asyncState = { spans: [] };
}
else {
asyncState = { spans: tslib_1.__spreadArrays(asyncState.spans) };
}
store.enterWith(asyncState);
return asyncState.spans;
};
ContextManager.prototype.clear = function (span) {
var spans = this.spansDup(); // this needed to make sure async tasks created before this call will still have this span at the top of their span list
var idx = spans.indexOf(span);
if (idx !== -1)
spans.splice(idx, 1);
};
ContextManager.prototype.restore = function (span) {
var spans = this.spansDup();
if (spans.indexOf(span) === -1)
spans.push(span);
};
ContextManager.prototype.removeTailFinishedContexts = function () {
// XXX: Normally, SpanContexts that finish and send their segments can remain in the span lists of async contexts.
// This is so that if an async child that was spawned by the original span code and is executed after the parent
// finishes and creates its own span can be linked to the parent segment and span correctly. But in some situations
// where successive independent operations are chained linearly instead of hierarchically (AWS Lambda functions),
// this can cause a false reference by a subsequent operation as if it were a child of the finished previous span.
for (var spans = this.asyncState.spans; spans.length && spans[spans.length - 1].context.finished; spans.pop())
;
};
ContextManager.prototype.withSpan = function (span, callback) {
var args = [];
for (var _i = 2; _i < arguments.length; _i++) {
args[_i - 2] = arguments[_i];
}
if (!span.startTime)
span.start();
try {
return callback.apply(void 0, args);
}
catch (e) {
span.error(e);
throw e;
}
finally {
span.stop();
}
};
ContextManager.prototype.withSpanAwait = function (span, callback) {
var args = [];
for (var _i = 2; _i < arguments.length; _i++) {
args[_i - 2] = arguments[_i];
}
return tslib_1.__awaiter(this, void 0, void 0, function () {
var e_1;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!span.startTime)
span.start();
_a.label = 1;
case 1:
_a.trys.push([1, 3, 4, 5]);
return [4 /*yield*/, callback.apply(void 0, args)];
case 2: return [2 /*return*/, _a.sent()];
case 3:
e_1 = _a.sent();
span.error(e_1);
throw e_1;
case 4:
span.stop();
return [7 /*endfinally*/];
case 5: return [2 /*return*/];
}
});
});
};
return ContextManager;
}());
exports.default = new ContextManager();
//# sourceMappingURL=ContextManager.js.map