From 235f635c822de5abcef4b5a252510cc65029613c Mon Sep 17 00:00:00 2001 From: wangyujie Date: Fri, 25 Apr 2025 11:36:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=96=B0=E5=A2=9E=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E6=8A=93=E5=8F=96longtrace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wangyujie --- record/record.js | 422 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 313 insertions(+), 109 deletions(-) diff --git a/record/record.js b/record/record.js index 2efc200..610314f 100644 --- a/record/record.js +++ b/record/record.js @@ -77,6 +77,7 @@ let htraceBuffer = new ArrayBuffer(0); let snapShotDur = 0; let snapShotCyclesNum = 0; let tmpTimeName = 0; +let longtraceFiles = []; // 创建logger const logger = winston.createLogger(require('../winston.config.js')); @@ -94,6 +95,7 @@ function process(session_id, cmd, message) { const params = JSON.parse(decode.decode(message)); logger.info(`获取到 params 参数`); + isLongTrace = params.isLongTrace; isRecordArkTs = params.isRecordArkTs; isRecordHitrace = params.isRecordHitrace; maxDur = params.maxDur; @@ -125,148 +127,349 @@ function process(session_id, cmd, message) { output = params.output; traceName = output.split('/').reverse()[0]; configText = params.htraceCmd.split('< { - recordArkts().then(res => { - const errorMsg = new Uint8Array(encoder.encode('Done')); - sendMsg(errorMsg, 8); - generateArktsTrace().then(res => { - combinedBufferData(); + ltOutput = 'data/local/tmp/long_trace'; + killCmd = 'killall hiprofilerd hiprofiler_plugins native_daemon hiperf hiebpf hiprofiler_cmd'; + chmodCmd ='chmod -R 777'; + recordHitraceCmd = isLongTrace ? `hiprofiler_cmd -c /${ltOutput}/config.text -o ${output} -t ${maxDur} -s -k` : `hiprofiler_cmd -c /data/local/tmp/config.text -o ${output} -t ${maxDur} -s -k`; + totalLength = 0; + + if (isLongTrace) { + delLongDir() + .then(makeLongDir) + .then(pushConfigText) + .then(sendLongtrace) + .catch(error => { + logger.error(`longtrace处理失败: ${error}`); + const errorMsg = new Uint8Array(encoder.encode(error)); + sendMsg(errorMsg, 3); + }); + } else { + if (isRecordArkTs && !isRecordHitrace && !isSnapshot) { + Promise.all([ + checkPortIfNeedRemove(), + watchPort() + ]).then(() => { + recordArkts().then(res => { + const errorMsg = new Uint8Array(encoder.encode('Done')); + sendMsg(errorMsg, 8); + generateArktsTrace().then(res => { + combinedBufferData(); + }).catch((error) => { + logger.info(`单独抓取 arkts 报错:${error}`); // 处理错误情况 + }); }).catch((error) => { logger.info(`单独抓取 arkts 报错:${error}`); // 处理错误情况 }); }).catch((error) => { logger.info(`单独抓取 arkts 报错:${error}`); // 处理错误情况 }); - }).catch((error) => { - logger.info(`单独抓取 arkts 报错:${error}`); // 处理错误情况 - }); - } + } - if (isRecordArkTs && !isRecordHitrace && isSnapshot) { - Promise.all([ - checkPortIfNeedRemove(), - watchPort(), - mkdirForSnapshot() - ]).then(() => { - recordArkts().then(res => { - const errorMsg = new Uint8Array(encoder.encode('Done')); - sendMsg(errorMsg, 8); - Promise.all([ - generateArktsTrace(), - saveSnapshot() - ]).then(res => { - combinedBufferData(); + if (isRecordArkTs && !isRecordHitrace && isSnapshot) { + Promise.all([ + checkPortIfNeedRemove(), + watchPort(), + mkdirForSnapshot() + ]).then(() => { + recordArkts().then(res => { + const errorMsg = new Uint8Array(encoder.encode('Done')); + sendMsg(errorMsg, 8); + Promise.all([ + generateArktsTrace(), + saveSnapshot() + ]).then(res => { + combinedBufferData(); + }).catch((error) => { + logger.info(`单独抓取 arkts + 截图 报错:${error} 0`); // 处理错误情况 + }); }).catch((error) => { - logger.info(`单独抓取 arkts + 截图 报错:${error} 0`); // 处理错误情况 + logger.info(`单独抓取 arkts + 截图 报错:${error} 1`); // 处理错误情况 }); }).catch((error) => { - logger.info(`单独抓取 arkts + 截图 报错:${error} 1`); // 处理错误情况 + logger.info(`单独抓取 arkts + 截图 报错:${error} 2`); // 处理错误情况 }); - }).catch((error) => { - logger.info(`单独抓取 arkts + 截图 报错:${error} 2`); // 处理错误情况 - }); - } + } - if (isRecordHitrace && !isRecordArkTs && !isSnapshot) { - pushConfigText().then(() => { - recordHitrace().then(res => { - const errorMsg = new Uint8Array(encoder.encode('Done')); - sendMsg(errorMsg, 8); - receiveHiTrace().then(res => { - combinedBufferData(); + if (isRecordHitrace && !isRecordArkTs && !isSnapshot) { + pushConfigText().then(() => { + recordHitrace().then(res => { + const errorMsg = new Uint8Array(encoder.encode('Done')); + sendMsg(errorMsg, 8); + receiveHiTrace().then(res => { + combinedBufferData(); + }).catch((error) => { + logger.info(`单独抓取 hitrace 报错:${error} 0`); // 处理错误情况 + }); }).catch((error) => { - logger.info(`单独抓取 hitrace 报错:${error} 0`); // 处理错误情况 + logger.info(`单独抓取 hitrace 报错:${error} 1`); // 处理错误情况 }); }).catch((error) => { - logger.info(`单独抓取 hitrace 报错:${error} 1`); // 处理错误情况 + logger.info(`单独抓取 hitrace 报错:${error} 2`); // 处理错误情况 }); - }).catch((error) => { - logger.info(`单独抓取 hitrace 报错:${error} 2`); // 处理错误情况 - }); - } + } - if (isRecordHitrace && !isRecordArkTs && isSnapshot) { - logger.info(`'isRecordHitrace': ${isRecordHitrace}`) - Promise.all([ - pushConfigText(), - mkdirForSnapshot() - ]).then(() => { - recordHitrace().then(res => { - const errorMsg = new Uint8Array(encoder.encode('Done')); - sendMsg(errorMsg, 8); - Promise.all([ - saveSnapshot(), - receiveHiTrace() - ]).then(res => { - combinedBufferData(); + if (isRecordHitrace && !isRecordArkTs && isSnapshot) { + logger.info(`'isRecordHitrace': ${isRecordHitrace}`) + Promise.all([ + pushConfigText(), + mkdirForSnapshot() + ]).then(() => { + recordHitrace().then(res => { + const errorMsg = new Uint8Array(encoder.encode('Done')); + sendMsg(errorMsg, 8); + Promise.all([ + saveSnapshot(), + receiveHiTrace() + ]).then(res => { + combinedBufferData(); + }).catch((error) => { + logger.info(`单独抓取 hitrace + 截图 报错:${error}`); // 处理错误情况 + }); }).catch((error) => { logger.info(`单独抓取 hitrace + 截图 报错:${error}`); // 处理错误情况 }); }).catch((error) => { logger.info(`单独抓取 hitrace + 截图 报错:${error}`); // 处理错误情况 }); - }).catch((error) => { - logger.info(`单独抓取 hitrace + 截图 报错:${error}`); // 处理错误情况 - }); - } + } - if (isRecordArkTs && isRecordHitrace && !isSnapshot) { - Promise.all([ - checkPortIfNeedRemove(), - watchPort(), - pushConfigText() - ]).then(() => { - recordHitrace().then(res => { - const errorMsg = new Uint8Array(encoder.encode('Done')); - sendMsg(errorMsg, 8); - Promise.all([ - receiveHiTrace() - ]).then(res => { - generateArktsTrace(); - }).then(res => { - combinedBufferData(); - }) + if (isRecordArkTs && isRecordHitrace && !isSnapshot) { + Promise.all([ + checkPortIfNeedRemove(), + watchPort(), + pushConfigText() + ]).then(() => { + recordHitrace().then(res => { + const errorMsg = new Uint8Array(encoder.encode('Done')); + sendMsg(errorMsg, 8); + Promise.all([ + receiveHiTrace() + ]).then(res => { + generateArktsTrace(); + }).then(res => { + combinedBufferData(); + }) + }).catch((error) => { + logger.info(`同时抓取 hitrace 和 arkts trace 报错:${error}`); // 处理错误情况 + }); }).catch((error) => { logger.info(`同时抓取 hitrace 和 arkts trace 报错:${error}`); // 处理错误情况 }); - }).catch((error) => { - logger.info(`同时抓取 hitrace 和 arkts trace 报错:${error}`); // 处理错误情况 - }); - } + } - if (isRecordArkTs && isRecordHitrace && isSnapshot) { - Promise.all([ - checkPortIfNeedRemove(), - watchPort(), - pushConfigText(), - mkdirForSnapshot() - ]).then(() => { - recordHitrace().then(res => { - const errorMsg = new Uint8Array(encoder.encode('Done')); - sendMsg(errorMsg, 8); - Promise.all([ - saveSnapshot(), - receiveHiTrace() - ]).then(res => { - generateArktsTrace(); - }).then(res => { - combinedBufferData(); - }) + if (isRecordArkTs && isRecordHitrace && isSnapshot) { + Promise.all([ + checkPortIfNeedRemove(), + watchPort(), + pushConfigText(), + mkdirForSnapshot() + ]).then(() => { + recordHitrace().then(res => { + const errorMsg = new Uint8Array(encoder.encode('Done')); + sendMsg(errorMsg, 8); + Promise.all([ + saveSnapshot(), + receiveHiTrace() + ]).then(res => { + generateArktsTrace(); + }).then(res => { + combinedBufferData(); + }) + }).catch((error) => { + logger.info(`同时抓取 hitrace 和 arkts trace + 截图 报错:${error}`); // 处理错误情况 + }); }).catch((error) => { logger.info(`同时抓取 hitrace 和 arkts trace + 截图 报错:${error}`); // 处理错误情况 }); - }).catch((error) => { - logger.info(`同时抓取 hitrace 和 arkts trace + 截图 报错:${error}`); // 处理错误情况 - }); + } } }; +function delLongDir() { + return new Promise((resolve, reject) => { + exec(`hdc shell ${killCmd}`, (error, stdout, stderr) => { + if (error || (stderr && stderr.length > 0) || stdout.includes('[Fail]')) { + const errorMsg = new Uint8Array(encoder.encode(stdout || error || stderr)); + sendMsg(errorMsg, 3); + reject(-1); + logger.error(`Failed to kill the plug-in service`); + return; + }; + resolve(0); + logger.info(`Succeeded in killing the plug-in service`); + }); + exec(`hdc shell rm -r /${ltOutput}/*`, (error, stdout, stderr) => { + logger.info(`delLongDir : ${error, stdout, stderr}`) + if (error || (stderr && stderr.length > 0) || stdout.includes('[Fail]')) { + const errorMsg = new Uint8Array(encoder.encode(stdout || error || stderr)); + sendMsg(errorMsg, 3); + reject(-1); + logger.error(`Failed to deleted long_trace folder`); + return; + }; + resolve(0); + logger.info(`Successfully deleted long_trace folder`); + }); + }); +} + +function makeLongDir() { + return new Promise((resolve, reject) => { + exec(`hdc shell mkdir /${ltOutput}/`, (error, stdout, stderr) => { + if (error || (stderr && stderr.length > 0) || stdout.includes('[Fail]')) { + const errorMsg = new Uint8Array(encoder.encode(stdout || error || stderr)); + sendMsg(errorMsg, 3); + reject(-1); + logger.error(`Failed to created long_trace folder`); + return; + }; + resolve(0); + logger.info(`Successfully created long_trace folder`); + }); + + exec(`hdc shell ${chmodCmd} /${ltOutput}/`, (error, stdout, stderr) => { + logger.info(`delAndMakeDir : ${error, stdout, stderr}`) + if (error || (stderr && stderr.length > 0) || stdout.includes('[Fail]')) { + const errorMsg = new Uint8Array(encoder.encode(stdout || error || stderr)); + sendMsg(errorMsg, 3); + reject(-1); + logger.error(`Failed chmod longtrace`); + return; + }; + resolve(0); + logger.info(`successfully chmod longtrace`); + }); + }); +} + + +function recordLongtrace() { + return new Promise((resolve, reject) => { + const hdc = spawn('hdc', ['-t', `${serialNum}`, 'shell', `${recordHitraceCmd}`]); + hdc.stdout.on('data', (data) => { + console.log(`longtrace标准输出:\n${data}`); + if (data.includes('DONE')) { + logger.info(`抓取 longtrace 命令执行完成`); + const errorMsg = new Uint8Array(encoder.encode('')); + sendMsg(errorMsg, 7); + resolve(0); + } + }); + + hdc.stderr.on('data', (data) => { + logger.info(`抓取 longtrace 命令执行错误`); + const errorMsg = new Uint8Array(encoder.encode(data)); + sendMsg(errorMsg, 3); + reject(-1); + }); + }) +} + + +function listLongtraceFiles() { + return new Promise((resolve, reject) => { + const command = `hdc -t ${serialNum} shell ls ${ltOutput}`; + exec(command, (error, stdout, stderr) => { + if (error) { + reject(`列出失败: ${stderr}`); + return; + } + const files = stdout.split('\n').filter(file => file.trim() !== ''); + resolve(files); + logger.info(`列出成功:${files}`) + }); + }); +} + + +function sendLongtrace() { + return new Promise((resolve, reject) => { + longtraceFiles = []; + recordLongtrace() + .then(() => { + return listLongtraceFiles() + .then(files => { + const savePath = `${directoryPath}/long_trace`; + if (fs.existsSync(savePath)) { + fs.rmSync(savePath, { recursive: true }); + } + fs.mkdirSync(savePath, { recursive: true }); + const allFiles = files.filter(file => file.trim() !== '' && file !== 'config.text\r'); + totalLength = allFiles.length; + const transferPromises = files.map(fileName => { + const remoteFilePath = `${ltOutput}/${fileName}`; + return transferFile(serialNum, remoteFilePath, savePath) + .then(() => { + if (fileName !== 'config.text\r') { + longtraceFiles.push({ + fileName: fileName, + localFilePath: `${directoryPath}\\long_trace\\${fileName}` + }); + } + }); + }); + return Promise.all(transferPromises); + }); + }) + .then(() => { + const cleanedFiles = longtraceFiles.map(file => ({ + fileName: file.fileName.replace(/\r$/, ''), + localFilePath: file.localFilePath.replace(/\r$/, '') + })); + + const readPromises = cleanedFiles.map(({ fileName, localFilePath }, index) => { + console.log('totalLength=>',totalLength) + return readAndSendFile(fileName, localFilePath, totalLength); + }); + + return Promise.all(readPromises); + }) + .then(() => { + logger.info(`longtrace处理成功`); + resolve(); + }) + .catch(error => { + logger.error(`longtrace处理失败: ${error}`); + reject(error); + }); + }); +} + +function transferFile(serialNum, remotePath, localPath) { + return new Promise((resolve, reject) => { + const command = `hdc -t ${serialNum} file recv ${remotePath} ${localPath}`; + exec(command, (error, stdout, stderr) => { + if (stdout.includes('FileTransfer finish')) { + resolve(); + } else if (stderr.includes('[Fail]')) { + reject(`文件传输失败: ${stderr}`); + } + }); + }); +} + +function readAndSendFile(fileName, localFilePath, total) { + return new Promise((resolve, reject) => { + if (!fs.existsSync(localFilePath)) { + reject(`${fileName}不存在`); + return; + } + fs.readFile(localFilePath, (err, data) => { + if (err) { + reject(`读取${fileName} 失败: ${err.message}`); + return; + } + const fileMessage = { + fileName, + total, + data: data.toString('base64') + }; + sendMsg(new TextEncoder().encode(JSON.stringify(fileMessage)), 9); + resolve(); + }); + }); +} + function combinedBufferData() { let finalBuffer = new ArrayBuffer(arktsBuffer.byteLength + htraceBuffer.byteLength) let traceView = new Uint8Array(finalBuffer); @@ -651,7 +854,8 @@ function pushConfigText() { }); // 将config文件推入手机里 logger.info(`config.text 文件推入手机开始`); - exec(`hdc -t ${serialNum} file send ${filePath} /data/local/tmp/config.text`, (error, stdout, stderr) => { + let cmd = isLongTrace ? `hdc -t ${serialNum} file send ${filePath} /${ltOutput}/config.text` : `hdc -t ${serialNum} file send ${filePath} /data/local/tmp/config.text` + exec(cmd, (error, stdout, stderr) => { if (stdout.includes('FileTransfer finish')) { logger.info(`config.text 文件推入手机结束`); resolve(0); -- Gitee