UNPKG

skywalking-backend-js-netease

Version:

The NodeJS agent for Apache SkyWalking

195 lines 8.84 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CommandProfileDump = void 0; const tslib_1 = require("tslib"); const http_grpc_pb_1 = require("../../../proto/tunnel/http_grpc_pb"); const http_pb_1 = require("../../../proto/tunnel/http_pb"); const AgentConfig_1 = tslib_1.__importDefault(require("../../../config/AgentConfig")); const AuthInterceptor_1 = tslib_1.__importDefault(require("../grpc/AuthInterceptor")); const logging_1 = require("../../../logging"); const grpc_js_1 = require("@grpc/grpc-js"); const inspector_1 = tslib_1.__importDefault(require("inspector")); const fs_1 = tslib_1.__importDefault(require("fs")); const path_1 = tslib_1.__importDefault(require("path")); const logger = logging_1.createLogger(__filename); const propertyKeys = new Map(); propertyKeys.set('product', { name: 'product', type: 'string' }); propertyKeys.set('service', { name: 'service', type: 'string' }); propertyKeys.set('node', { name: 'node', type: 'string' }); propertyKeys.set('taskId', { name: 'taskId', type: 'string' }); propertyKeys.set('type', { name: 'type', type: 'string' }); propertyKeys.set('createTime', { name: 'createTime', type: 'number' }); propertyKeys.set('duration', { name: 'duration', type: 'number' }); class CommandProfileDump { constructor() { this.options = () => { return { deadline: Date.now() + 30000 }; }; this.session = new inspector_1.default.Session(); } start() { this.session.connect(); this.url = `http://127.0.0.1:11800/${AgentConfig_1.default.authorization}/profile/dump`; this.httpReportServiceClient = new http_grpc_pb_1.HttpReportServiceClient(AgentConfig_1.default.collectorAddress, AgentConfig_1.default.secure ? grpc_js_1.credentials.createSsl() : grpc_js_1.credentials.createInsecure()); this.session.post('Profiler.enable', (err) => { if (err) { logger.error(`Error Profile cpu enable sampler`, err); return; } }); this.session.post('HeapProfiler.enable', (err) => { if (err) { logger.error(`Error Profile heap enable sampler`, err); return; } }); } execute(cmd) { const props = {}; cmd.getArgsList() .sort((a, b) => a.getKey().localeCompare(b.getKey())) .forEach(arg => { if (arg.getKey() === 'SerialNumber') { return; } if (propertyKeys.has(arg.getKey())) { const prop = propertyKeys.get(arg.getKey()); props[prop.name] = convert(arg.getValue(), prop.type); logger.info(`Profile dump config ${arg.getKey()} = ${arg.getValue()}`); } }); props['startTime'] = Date.now(); const fileName = `profile-${props['startTime']}`; // do with profile switch (props['type'] || 'cpu') { case 'cpu': this.profile(props, fileName); break; case 'heap': this.heapprofile(props, fileName); break; case 'dump': this.heapdump(props, fileName); break; } } profile(props = {}, fileName) { const duration = (props['duration'] || 60 * 1000); // to millisecond props['uri'] = path_1.default.join(AgentConfig_1.default.dumpFilePath, `${fileName}.cpuprofile`); this.session.post('Profiler.start', (err) => { if (err) { logger.error(`Error Profile cpu start sampler`, err); return; } setTimeout(() => { // some time later... this.session.post('Profiler.stop', (err, { profile }) => { // Write profile to disk props['stopTime'] = Date.now(); props['duration'] = props['stopTime'] - props['startTime']; if (!err) { this.writeData(props, profile); logger.debug(`send profile result info to collector, ${JSON.stringify(props)}`); this.send(props) .then(() => { logger.info(`Success Profile Node.js, file is ${props['uri']}`); }).catch(err => { logger.error(`Success Profile Node.js, file is ${props['uri']}, but send info to collector error`, err); }); } else { logger.error(`Error Profile dump cpu do sampler for task ${props['uri']}`, err); } }); }, duration); }); } heapprofile(props = {}, fileName) { const duration = (props['duration'] || 60 * 1000); // to millisecond props['uri'] = path_1.default.join(AgentConfig_1.default.dumpFilePath, `${fileName}.heapprofile`); this.session.post('HeapProfiler.startSampling', (err) => { if (err) { logger.error(`Error Profile heap start sampler`, err); return; } setTimeout(() => { // some time later... this.session.post('HeapProfiler.stopSampling', (err, { profile }) => { // Write profile to disk props['stopTime'] = Date.now(); props['duration'] = props['stopTime'] - props['startTime']; if (!err) { this.writeData(props, profile); logger.debug(`send profile result info to collector, ${JSON.stringify(props)}`); this.send(props) .then(() => { logger.info(`Success Profile Node.js, file is ${props['uri']}`); }).catch(err => { logger.error(`Success Profile Node.js, file is ${props['uri']}, but send info to collector error`, err); }); } else { logger.error(`Error Profile dump cpu do sampler for task ${props['uri']}`, err); } }); }, duration); }); } heapdump(props = {}, fileName) { props['uri'] = path_1.default.join(AgentConfig_1.default.dumpFilePath, `${fileName}.heapsnapshot`); const res = []; const getChunk = (m) => { res.push(m.params.chunk); }; this.session.on('HeapProfiler.addHeapSnapshotChunk', getChunk); this.session.post('HeapProfiler.takeHeapSnapshot', {}, (err) => { this.session.removeListener('HeapProfiler.addHeapSnapshotChunk', getChunk); if (err) { logger.error(`Error Profile dump heap for task ${props['uri']}`, err); } else { this.writeData(props, JSON.parse(res.join(''))); props['stopTime'] = Date.now(); props['duration'] = props['stopTime'] - props['startTime']; logger.debug(`send profile result info to collector, ${JSON.stringify(props)}`); this.send(props) .then(() => { logger.info(`Success Profile Node.js, file is ${props['uri']}`); }).catch(err => { logger.error(`Success Profile Node.js, file is ${props['uri']}, but send info to collector error`, err); }); } }); } send(prop = {}) { return new Promise((resolve, reject) => { const stream = this.httpReportServiceClient.invoke(AuthInterceptor_1.default(), this.options(), (err, resp) => { if (err) { reject(err); return; } resolve({ code: resp.getCode(), body: resp.getBody() }); }); const req = new http_pb_1.HttpReqObject() .setMethod("PUT") .setUrl(this.url) .setBody(new TextEncoder().encode(JSON.stringify(prop))) .setHeadersList([new http_pb_1.PairObject().setKey("Content-Type").setValue("application/json")]); stream.write(req); stream.end(); }); } writeData(props = {}, data) { fs_1.default.writeFileSync(props['uri'], JSON.stringify(data)); } } exports.CommandProfileDump = CommandProfileDump; function convert(val, type) { switch (type) { case 'boolean': return 'true' === val; case 'number': return +val || 0; default: return val; } } //# sourceMappingURL=CommandProfileDump.js.map