以前交接過來的工做裏有個頁面本地調試麻煩,由於它的數據是後端實時上報而來,每次一報bug,都是給一個幾兆的日誌文本(上面記錄了實際出問題的上報數據【json格式】),經過肉眼分析日誌搭配頁面邏輯人工解讀,太難了……後面在頁面加了mock的邏輯,但遇到一個問題,就是把日誌中的數據配置到mock接口那邊 node
=> 因而有了寫腳本從日誌文件裏提取json數據的想法。json
替換方案:來自Stack Overflow>>後端
原理:經過對字符串進行"{}"識別和截取,利用JSON.parse對截取的字符串進行嘗試轉換,若是成功則返回,失敗(拋出異常)則捕獲異常並繼續縮窄字符串內容範圍。編輯器
該段原理邏輯識別不了全部json,優先匹配第一個出現的json,我改爲了從後往前來識別json,主要是結合需求的日誌重點在後面的jsonpost
function extractJSON(str) { var firstOpen, firstClose = str.length - 1, candidate; firstClose = str.lastIndexOf('}'); do { // debugger firstOpen = str.indexOf('{'); // console.log('firstOpen: ' + firstOpen, 'firstClose: ' + firstClose); if(firstClose <= firstOpen) { return null; } do { candidate = str.substring(firstOpen, firstClose + 1); // console.log('candidate: ' + candidate); try { var res = JSON.parse(candidate); return [res, firstOpen, firstClose + 1]; } catch(e) { // console.log('...failed'); } firstOpen = str.indexOf('{', firstOpen+1); } while(firstClose > firstOpen && firstOpen !== -1); firstClose = str.lastIndexOf('}', firstClose - 1); } while(firstClose != -1); return null; }
如此,就能夠解決如何從一段文本中提取出json內容來。ui
接下來就是如何合理提取json爲好,日誌文件內容的特徵是每行輸出信息,而基本每行能提取一個關鍵json的數據來,那麼能夠用上nodejs的流來實現按行讀取同時提取jsondebug
參考>>調試
注:只是看中了用stream來處理文件讀取方便,對於較爲大一點的文件(我遇到的日誌最大不超過1g),能夠按參考連接裏的event-stream來處理日誌
該部分的內容就不作重複說明,直接貼代碼。code
const fs = require('fs'); const readline = require('readline'); const stream = require('stream'); const instream = fs.createReadStream('test.log.txt'); const outstream = new stream(); const rl = readline.createInterface(instream, outstream); function extractJSON(str) { var firstOpen, firstClose = str.length - 1, candidate; firstClose = str.lastIndexOf('}'); do { // debugger firstOpen = str.indexOf('{'); // console.log('firstOpen: ' + firstOpen, 'firstClose: ' + firstClose); if(firstClose <= firstOpen) { return null; } do { candidate = str.substring(firstOpen, firstClose + 1); // console.log('candidate: ' + candidate); try { var res = JSON.parse(candidate); // console.log('...found'); return [res, firstOpen, firstClose + 1]; } catch(e) { // console.log('...failed'); } firstOpen = str.indexOf('{', firstOpen+1); } while(firstClose > firstOpen && firstOpen !== -1); firstClose = str.lastIndexOf('}', firstClose - 1); } while(firstClose != -1); return null; } // 記錄行數 let lineCount = 0; // 收集json數據 const results = []; rl.on("line", lineStr => { lineCount++; const extractRes = extractJSON(lineStr); if (extractRes) { results.push({ line: lineCount, content: extractRes[0] }) } }); rl.on('close', () => { // 對收集來的json數據再作一下過濾,提取目標json const fileContents = results.filter(res => res.content.msg_content); // 通常結果都很多,直接寫入輸出文件中 fs.writeFileSync('res.txt', fileContents.map(obj => { return ' 行:' + obj.line + '\n' + JSON.stringify(obj.content); }).join('\n\n')); });
如此一來,寫好腳本之後就方便過濾日誌文件提取必要信息用於分析了,也能夠拿來mock用。
發現從code上覆制的代碼貼到sf編輯器,會加入\
的轉義符,還得複製到sublime 再複製回來才正常 - -||