Flog.js
Emeditor用的格式化日志的脚本。
主要用于从日期中提取行列数据。
// 功能:格式化runlog中各个线程的统计项 // 使用方法,输入所要提取统计项的一个关键词,或多个关键词对应值求和 // 正则无记忆方法 var fso = new ActiveXObject("Scripting.FileSystemObject"); var strSplitter = "\t"; var WshShell = new ActiveXObject("WScript.Shell"); var g_ScriptName; var g_ScriptContainFolder; var g_TmpFolder; // 一堆开关 var g_bAllowMulti; var g_arrayLog = new Array(); function Log(str) { g_arrayLog.push(str); } function Output(str) { WScript.StdOut.WriteLine(str); } function SetPriorityLow(processId) { var WMI = GetObject("WinMgmts:"); var sCmdQuery = "Select * from Win32_Process where ProcessId = " + processId; var cmds = WMI.ExecQuery(sCmdQuery); if(cmds.Count != 1) { return 0; } /* 64 低 32 标准 128 高 256 实时 Idle 低 Below Normal 低于标准 Normal 标准 Above Normal 高于标准 High Priority 高 Realtime 实时 */ try { cmds.ItemIndex(0).SetPriority(64); } catch (e) { WriteConsole("Process" + processId + " setpriority failed"); } } RegExp.prototype.TestNoRecord = function(str){ var ret = this.test(str); this.lastIndex = 0; return ret; } RegExp.prototype.ExecNoRecord = function(str){ var ret = this.exec(str); this.lastIndex = 0; return ret; } // 数组排重插入方法 Array.prototype.Insert = function(val) { for(var i = 0; i < this.length; ++i) { if(this[i] == val) { return false; } } this.push(val); return true; } Array.prototype.Delete = function(i) { this.splice(i, 1); } function IsBigger(val1, val2) { var bIsVal1Number = !isNaN(val1); var bIsVal2Number = !isNaN(val2); if(bIsVal1Number) { if(bIsVal2Number) { return (parseInt(val1) > parseInt(val2)); } else { return false; } } else { if(bIsVal2Number) { return true; } else { return (val1 > val2); } } } function ParseInt(strVal) { var iRet = 0; if(strVal.length > 2 && '0' == strVal.charAt(0) && 'x' == strVal.charAt(1)) { //0x for(var i = 2; i < strVal.length; ++i) { var cVal = strVal.charAt(i); var iVal = 0; if(cVal >= '0' && cVal <= '9') { iVal = cVal - '0'; } else if(cVal >= 'a' && cVal <= 'f') { switch(cVal) { case 'a': { iVal = 10; break; } case 'b': { iVal = 11; break; } case 'c': { iVal = 12; break; } case 'd': { iVal = 13; break; } case 'e': { iVal = 14; break; } default: { iVal = 15; break; } } } else { return 0; } iRet = iRet * 16 + iVal; } } else { var lAfterPointStep = 0; for(var i = 0; i < strVal.length; ++i) { var cVal = strVal.charAt(i); if(',' == cVal || ' ' == cVal) { continue; } if('.' == cVal) { if(lAfterPointStep != 0) { // 重复点 return -999999999; } lAfterPointStep = 1; continue; } if(cVal < '0' && cVal > '9') { return -999999999; } if(lAfterPointStep) { lAfterPointStep = lAfterPointStep / 10; iRet += (cVal - '0') * lAfterPointStep; } else { iRet = iRet * 10 + (cVal - '0'); } } } return iRet; } Array.prototype.Sort = function() { for(var i = 0; i < (this.length - 1); ++i) { var bSorted = false; for(var j = 0; j < (this.length - i - 1); ++j) { if(IsBigger(this[j], this[j + 1])) { tmp = this[j]; this[j] = this[j+1]; this[j+1] = tmp; bSorted = true; } } if(!bSorted) { break; } } } // 数组拷贝方法,数组直接赋值只相当于赋值引用 Array.prototype.Copy = function() { // 重新生成一个数组返回出去 var ret = new Array(); return ret.concat(this); } // 数组清空方法 Array.prototype.Clear = function() { this.splice(0, this.length); } function GetTmpFolder() { var objRet; var tmpFolder = fso.GetSpecialFolder(2); // 遍历文件夹 var foldersK = new Enumerator(tmpFolder.SubFolders); if(!fso.FolderExists(tmpFolder.Path + "\\" + g_ScriptName)) { tmpFolder.SubFolders.Add(g_ScriptName); } objRet = fso.GetFolder(tmpFolder.Path + "\\" + g_ScriptName); return objRet; } function Row(strRow) { this.m_strRow = strRow; this.m_aryColumns = new Array(); this.ToString = function() { var strRet = this.m_strRow; for(var i = 0; i < this.m_aryColumns.length; ++i) { strRet += strSplitter + this.m_aryColumns[i].ToString(); } return strRet; } this.ToInt = function() { var iRet = 0; for(var i = 0; i < this.m_aryColumns.length; ++i) { iRet += this.m_aryColumns[i].ToInt(); } return iRet; } this.ToString4Specified = function(specified) { //debugger; var iSum = 0; var strRet = this.m_strRow; for(var i = 0; i < specified.length; ++i) { var strTmp = ""; for(var j = 0; j < this.m_aryColumns.length; ++j) { if(this.m_aryColumns[j].m_strId == specified[i]) { var iTmp = this.m_aryColumns[j].ToInt(); strTmp = iTmp.toString(); iSum += iTmp; break; } } if(j == this.m_aryColumns.length) { if("sum" == specified[i]) { strTmp = iSum.toString(); } else { strTmp = new Column(specified[i], 0).ToInt().toString(); } } strRet += strSplitter + strTmp; } return strRet; } this.HasValueColumns = function() { var ret = new Array(); for(var i = 0; i < this.m_aryColumns.length; ++i) { if(this.m_aryColumns[i].HasValue()) { ret.push(this.m_aryColumns[i].m_strId); } } return ret; } this.Learn = function(another) { var anotheraryColumns = another.m_aryColumns.Copy(); for(var i = 0; i < this.m_aryColumns.length; ++i) { for(var j = 0; j < anotheraryColumns.length; ++j) { if(anotheraryColumns[i].m_strId == this.m_aryColumns[i].m_strId) { // 同一列合入 this.m_aryColumns[i].Learn(anotheraryColumns[i]); anotheraryColumns.Delete(i); break; } } } for(var i = 0; i < anotheraryColumns.length; ++i) { // 不同列从后面压入 this.m_aryColumns.push(anotheraryColumns[i]); } } this.Merge = function(another) { //debugger; for(var i = 0; i < another.m_aryColumns.length; ++i) { var column = another.m_aryColumns[i]; var bExist = true; var k = 0; var strNewId = ""; while(bExist) { bExist = false; strNewId = column.m_strId + "_" + k; for(var j = 0; j < this.m_aryColumns.length; ++j) { if(strNewId == this.m_aryColumns[j].m_strId) { bExist = true; ++k; break; } } }column.m_strId = strNewId; this.m_aryColumns.push(column); } } } function decimal(num,v) { var vv = Math.pow(10,v); return Math.round(num*vv)/vv; } function Column(strId, typeNum) { this.m_strId = strId; // 每个正则式分配一个位置存值 this.m_aryValues = new Array(typeNum); for(var i = 0; i < typeNum; ++i) { this.m_aryValues[i] = new Array(); } this.AddValue = function(typeId, strVal) { this.m_aryValues[typeId].push(strVal); } this.ToInt = function() { var iRet = 0; for(var i = 0; i < this.m_aryValues.length; ++i) { var tmpValue = this.m_aryValues[i]; for(var j = 0; j < tmpValue.length; ++j) { iRet += ParseInt(tmpValue[j]); } if(!g_bAllowMulti && (j > 1)) { Log("Multi exist!!!"); } } return decimal(iRet, 6); } this.HasValue = function() { for(var i = 0; i < this.m_aryValues.length; ++i) { var tmpValue = this.m_aryValues[i]; if(tmpValue.length > 0) { return true; } } return false; } this.Learn = function(another) { for(var i = 0; i < this.m_aryValues.length; ++i) { this.m_aryValues[i] = this.m_aryValues[i].concat(another.m_aryValues[i]); } } } function ExistFileOrFolder(strPath) { if(fso.FileExists(strPath)) { return true; } if(fso.FolderExists(strPath)) { return true; } return false; } function ExistInArray(aryValues, value) { for(var i = 0; i < aryValues.length; ++i) { if(aryValues[i] == value) { return true; } } return false; } function GetRandomFileName() { return ("-" + Math.floor(Math.random() * 999)); } function OpenResult(strResultPath) { strOpenCmd = "\"" + g_ScriptContainFolder.ParentFolder + "\\" + "EmEditor.exe " + "\"" + " /r " + "\"" + strResultPath + "\""; WshShell.Run(strOpenCmd, 10, true); var objOutPutFile = fso.GetFile(strResultPath); objOutPutFile.Delete(true); } function RegManager() { // 选择一个后后续就用一个了 this.m_reg = null; this.m_regs = new Array(); this.Add = function(reg) { this.m_regs.push(reg); } this.ExecNoRecord = function(strSource) { if(this.m_reg) { return this.m_reg.ExecNoRecord(strSource); } else { for(var i = 0; i < this.m_regs.length; ++i) { var reret = this.m_regs[i].ExecNoRecord(strSource); if(reret) { this.m_reg = this.m_regs[i]; return reret; } } return null; } } } function Parser(regRow, regColumn, aryValRegPatterns) { this.m_regRow = regRow; this.m_regColumn = regColumn; this.m_aryValRegPatterns = aryValRegPatterns.Copy(); this.Process = function(objFileStream) { var aryOutput = new Array(); var tmpOutput; var tmpColumn; while (!objFileStream.AtEndOfStream) { var strContentLine = objFileStream.ReadLine(); var reRowRet = this.m_regRow.ExecNoRecord(strContentLine); if(reRowRet) { tmpOutput = new Row(reRowRet[1]); // 增加查找重复行操作,只需回差上面一个即可 aryOutput.push(tmpOutput); // 支持非线程部分 tmpColumn = new Column("all", this.m_aryValRegPatterns.length); tmpOutput.m_aryColumns.push(tmpColumn); continue; } if(tmpOutput) { var reColumnRet = this.m_regColumn.ExecNoRecord(strContentLine); if(reColumnRet) { tmpColumn = new Column(reColumnRet[1], this.m_aryValRegPatterns.length); tmpOutput.m_aryColumns.push(tmpColumn); continue; } if(tmpColumn) { for(var i = 0; i < this.m_aryValRegPatterns.length; ++i) { var regVal = this.m_aryValRegPatterns[i]; var reret3 = regVal.ExecNoRecord(strContentLine); if(reret3) { tmpColumn.AddValue(i, reret3[1]); continue; } } } } } //debugger; return aryOutput; } } // 空白周期检测 function Recycle() { this.m_uiStat = 0;// 0,1,2,3,4,5 0啥没做,1第二个元素,2切换为空状态,3切换为空状态,4 切换为空状态已经准备好,5 匹配已经失败 this.m_iHeaderCount = 0; this.m_iValueCount = 0; this.m_iEmptyCount = 0; this.m_iCurrentCount = 0; this.m_bLastHastValue = false; this.m_iMatchedCount = 0; this.Check = function(bHasValue) { switch(this.m_uiStat) { case 0: { this.m_uiStat = 1; break; } case 1: { if(this.m_bLastHastValue != bHasValue) { this.m_iHeaderCount = this.m_iCurrentCount; this.m_uiStat = 2; this.m_iCurrentCount = 0; } break; } case 2: { if(this.m_bLastHastValue != bHasValue) { if(this.m_bLastHastValue) { this.m_iValueCount = this.m_iCurrentCount; } else { this.m_iEmptyCount = this.m_iCurrentCount; } this.m_uiStat = 3; this.m_iCurrentCount = 0; } break; } case 3: { if(this.m_bLastHastValue != bHasValue) { if(this.m_bLastHastValue) { this.m_iValueCount = this.m_iCurrentCount; } else { this.m_iEmptyCount = this.m_iCurrentCount; } if(this.m_iHeaderCount <= this.m_iCurrentCount) { this.m_uiStat = 4; } else { this.m_uiStat = 5; } this.m_iCurrentCount = 0; } break; } case 4: { if(this.m_bLastHastValue != bHasValue) { var bMatched = this.m_bLastHastValue ? (this.m_iValueCount == this.m_iCurrentCount) : (this.m_iEmptyCount == this.m_iCurrentCount); if(!bMatched) { this.m_uiStat = 5; } else { this.m_iMatchedCount++; } this.m_iCurrentCount = 0; } break; } case 5: { if(this.m_bLastHastValue != bHasValue) { this.m_iCurrentCount = 0; } break; } } this.m_iCurrentCount++; this.m_bLastHastValue = bHasValue; } this.OK = function() { return ((4 == this.m_uiStat) && (this.m_iMatchedCount >= 2) && (this.m_bLastHastValue ? (this.m_iCurrentCount <= this.m_iValueCount) : (this.m_iCurrentCount <= this.m_iEmptyCount))); } } function Proc(objParser, strFilePath, bOpenResult, strRenameTo, bAnalyse, bRegular, bDropEmpty) { var objFile = fso.OpenTextFile(strFilePath, 1 , false); var aryOutput = objParser.Process(objFile); objFile.Close(); // 重复空值检测 var valueFlag = new Array(); var recycle= new Recycle(); var columnsToOutput = new Array() for(var i = 0; i < aryOutput.length; ++i) { var ret = aryOutput[i].HasValueColumns(); /*排除重复空值 var j = i + 1; for(; j < aryOutput.length; ) { if(aryOutput[j].m_strRow == aryOutput[i].m_strRow) { var retTmp = aryOutput[j].HasValueColumns(); if(0 == retTmp.length) { aryOutput.Delete(j); } else if(0 == ret.length) { aryOutput.Delete(i); ret = retTmp.Copy(); } else { break; } } else { break; } }*/ var bHasValue = (0 != ret.length) valueFlag.push(ret); recycle.Check(bHasValue); for(var k = 0; k < ret.length; ++k) { columnsToOutput.Insert(ret[k]); } } if(recycle.OK()) { for(var i = 0; i < valueFlag.length;) { if(0 == valueFlag[i].length) { valueFlag.Delete(i); aryOutput.Delete(i); } else { ++i; } } Log("recycle empty deleted!!!"); } // 重复行号周期检测 var bDumplicateTestResult = false; var iCurrentDumplicateCount = 1; var iDumplicateCount = 0; for(var i = 1; i < aryOutput.length; ++i) { if(aryOutput[i].m_strRow != aryOutput[i - 1].m_strRow) { if(iDumplicateCount == 0) { iDumplicateCount = iCurrentDumplicateCount; } else { if(iCurrentDumplicateCount != iDumplicateCount) { break; } } iCurrentDumplicateCount = 1; } else { ++iCurrentDumplicateCount; } } if(i == aryOutput.length) { if(iCurrentDumplicateCount == iDumplicateCount) { bDumplicateTestResult = iDumplicateCount > 1; } else { bDumplicateTestResult = iDumplicateCount > 2; } } if(bDumplicateTestResult) { if(columnsToOutput.length == 1) { columnsToOutput.Clear(); for(var i = 0; i < (aryOutput.length - 1); ++i) { var j = i + 1; for(; j < aryOutput.length; ) { if(aryOutput[j].m_strRow == aryOutput[i].m_strRow) { aryOutput[i].Merge(aryOutput[j]); aryOutput.Delete(j); } else { break; } } var ret = aryOutput[i].HasValueColumns(); for(var k = 0; k < ret.length; ++k) { columnsToOutput.Insert(ret[k]); } } Log("duplicate row merged!!!"); } else { for(var i = 0; i < (aryOutput.length - 1); ++i) { var j = i + 1; for(; j < aryOutput.length; ) { if(aryOutput[j].m_strRow == aryOutput[i].m_strRow) { aryOutput[i].Learn(aryOutput[j]); aryOutput.Delete(j); } else { break; } } } Log("duplicate row sumed!!!"); } } if(columnsToOutput.length == 0 && bDropEmpty && !bOpenResult) { Output("!!!" + strRenameTo + " droped!!!"); return; } var objResultFolder; if(bOpenResult) { objResultFolder = g_TmpFolder; } else { objResultFolder = fso.GetFile(strFilePath).ParentFolder; } var strFileName = fso.GetFile(strFilePath).Name; var iFileNameNo = 0; var strWriteToPath = ""; do { var strSubFileName = strFileName + "_" + strRenameTo; if(iFileNameNo > 0) { strSubFileName += "_" + iFileNameNo; } strSubFileName += Math.round((Math.random() * 1000)); strSubFileName += ".tsv"; strWriteToPath = objResultFolder.Path + "\\" + strSubFileName; ++iFileNameNo; } while(ExistFileOrFolder(strWriteToPath)) var objOutPutTextStream = fso.OpenTextFile(strWriteToPath, 2 , true); // objOutPutTextStream.WriteLine(strFilePath); // objOutPutTextStream.WriteLine(strKeys); var strHeader = "Row"; columnsToOutput.Sort(); if(columnsToOutput.length > 1) { columnsToOutput.Insert("sum"); } for(var i = 0; i < columnsToOutput.length; ++i) { strHeader += strSplitter + columnsToOutput[i]; } objOutPutTextStream.WriteLine(strHeader); for(var i = 0; i < aryOutput.length; ++i) { objOutPutTextStream.WriteLine(aryOutput[i].ToString4Specified(columnsToOutput)); } objOutPutTextStream.WriteLine(); for(var i = 0; i < g_arrayLog.length; ++i) { objOutPutTextStream.WriteLine(g_arrayLog[i]); } objOutPutTextStream.Close(); if(bAnalyse) { Output(strWriteToPath); var aryTmpSum = new Array(); for(var i = 0; i < aryOutput.length; ++i) { aryTmpSum.push(aryOutput[i].ToInt()); } if(aryTmpSum.length > 1) { var aryTmpSumDiff = new Array(); var iMaxDiff = 0; var iMinDiff = Number.MAX_VALUE; var iDiffSum = 0; for(var i = 1; i < aryTmpSum.length; ++i) { var tmpSumDiff = aryTmpSum[i] - aryTmpSum[i - 1]; aryTmpSumDiff.push(tmpSumDiff); if(tmpSumDiff < 0) { tmpSumDiff = 0 - tmpSumDiff; } if(tmpSumDiff > iMaxDiff) { iMaxDiff = tmpSumDiff; } if(tmpSumDiff < iMinDiff) { iMinDiff = tmpSumDiff; } iDiffSum += tmpSumDiff; } var iAvgDiff = iDiffSum / aryTmpSumDiff.length; var strResult = "MaxDiff:\t" + iMaxDiff + "\t" + ((iMaxDiff - iAvgDiff) / iAvgDiff).toFixed(2); strResult += "\n" + "MinDiff:\t" + iMinDiff + "\t" + ((iAvgDiff - iMinDiff) / iAvgDiff).toFixed(2); strResult += "\n" + "AvgDiff:\t" + iAvgDiff.toFixed(2); Output(strResult); } } if(bOpenResult) { OpenResult(strWriteToPath); } } function GetAvailablePath() { do { var strSubFileName = Math.round((Math.random() * 1000)); strSubFileName += ".txt"; var strRet = g_TmpFolder + "\\" + strSubFileName; if(fso.FolderExists(strRet)) { continue; } if(fso.FileExists(strRet)) { var file = fso.GetFile(strPath).DateLastModified; if(!(((new Date()).getTime() - (new Date(fso.GetFile(strPath).DateLastModified)).getTime()) / (3600 * 1000))) { continue; } } return strRet; } while(true) } function main() { var bExistWScript = false; try { if(WScript) { bExistWScript = true; } } catch(e){} if(!bExistWScript) { g_ScriptName = ScriptName; g_ScriptFullName = ScriptFullName; } else { g_ScriptName = WScript.ScriptName; g_ScriptFullName = WScript.ScriptFullName } // 全局变量初始化 g_ScriptContainFolder = fso.GetFile(g_ScriptFullName).ParentFolder; g_TmpFolder = GetTmpFolder(); if(!bExistWScript) { var strCmd = ""; var strAnswer = prompt("Count Item:", ""); if(strAnswer == "") { return; } var documentFullName = ""; if(!document.Saved) { documentFullName = GetAvailablePath(); var objTmpStream = fso.OpenTextFile(documentFullName, 2 , true); var nLines = document.GetLines(); for(var i = 1; i <= nLines; ++i) { objTmpStream.WriteLine(document.GetLine(i)); } objTmpStream.Close(); } else { documentFullName = document.FullName; } strCmd = "cscript /d " + "\"" + ScriptFullName + "\"" + " " + "\"" + documentFullName + "\"" + " " + "\"" + strAnswer + "\""; var objTmpStream = fso.OpenTextFile(ScriptFullName + ".txt", 8 , true); objTmpStream.WriteLine(strCmd); objTmpStream.Close(); //Emeditor无法隐藏exec执行时的窗口。 WshShell.Run(strCmd, 0, false); //var process = WshShell.Exec("cscript D:\\PersonalSet\\Desktop\\sleep10.js"); //SetPriorityLow(process.ProcessId); //Sleep(10000); return; } else { if((WScript.Arguments.length >= 2) && (WScript.Arguments(0) !="") && (WScript.Arguments(1) != "")) { var bOpenResult = true; var bAnalyse = false; var bRegular = false; var bAllowMulti = true; var bDropEmpty = false; if(WScript.Arguments.length > 2) { var strOptionList = WScript.Arguments(2); var aryOptions = strOptionList.split("|"); if(ExistInArray(aryOptions, "NotOpen")) { bOpenResult = false; } if(ExistInArray(aryOptions, "Analyse")) { bAnalyse = true; } if(ExistInArray(aryOptions, "Regular")) { bRegular = true; } if(ExistInArray(aryOptions, "OnlyFirstValue")) { bAllowMulti = false; } if(ExistInArray(aryOptions, "DropEmpty")) { bDropEmpty = true; } } g_bAllowMulti = bAllowMulti; var strRenameTo = ""; if(WScript.Arguments.length >=4) { strRenameTo = WScript.Arguments(3); } var strKeys = WScript.Arguments(1); var aryValRegPatterns = new Array(); if(bRegular) { var strAnswerPart = strKeys; var strValRgePattern = "^" + strAnswerPart + "\\s*((\\d+)|(\\d+\\.\\d+)|(\\d{1,3}(\\,\\d{3})+)|(0x[0-9,a-f]+))\\s*$"; var regVal = new RegExp(strValRgePattern, "gm"); aryValRegPatterns.push(regVal); } else { var aryKeys = strKeys.split("|"); for(var i = 0; i < aryKeys.length; ++i) { var strAnswerPart = aryKeys[i].replace(/([\[\]\(\)\-\:])/gm, "\\$1"); strValRgePattern = "^" + strAnswerPart + "\\s*((\\d+)|(\\d+\\.\\d+)|(\\d{1,3}(\\,\\d{3})+)|(0x[0-9,a-f]+))\\s*$"; var regVal = new RegExp(strValRgePattern, "gm"); aryValRegPatterns.push(regVal); } } var regRow = new RegManager(); regRow.Add(/^OutputTime\:\s*(\d{4}-\d{2}-\d{2} \d{2}\:\d{2}\:\d{2}).*$/gm);// 时间正则表达式 regRow.Add(/^#DateTime Stamp\: (\d{4}\-\d{2}\-\d{2} \d{2}\:\d{2}\:\d{2})\.\d{3}$/gm); var regColumn = new RegManager(); regColumn.Add(/^Thread\[(\d+)\]\:.*$/gm);// 分列正则表达式 var objParser = new Parser(regRow, regColumn, aryValRegPatterns); if(strRenameTo == "") { strRenameTo = strKeys.replace(/[\(\)\-\:\|\>\<\s]/gm, "_"); strRenameTo = strRenameTo.replace(/\_+/gm, "_"); } Proc(objParser, WScript.Arguments(0), bOpenResult, strRenameTo, bAnalyse, bRegular, bDropEmpty); return; } } /*if(document.Saved) { var fso = new ActiveXObject("Scripting.FileSystemObject"); var objFile = fso.OpenTextFile(document.FullName, 1 , false); while (!objFile.AtEndOfStream) { Parser(objFile.ReadLine()); } } else { document.selection.SelectAll(); var strContent = document.selection.Text; document.selection.StartOfLine(); var aryContent = strContent.split("\n"); for(var i = 0; i < aryContent.length; ++i) { Parser(aryContent[i]); } }*/ } main();