public IEnumerator GetEnumerator() { string strError = ""; int nRet = 0; if ((this.LogType & LogType.AccessLog) != 0 && (this.LogType & LogType.OperLog) != 0) { throw new ArgumentException("OperLogLoader 的 LogType 只能使用一种类型"); } if (string.IsNullOrEmpty(this.CacheDir) == false) { TryCreateDir(this.CacheDir); } // ProgressEstimate estimate = new ProgressEstimate(); bool bAutoCache = this.AutoCache; if (bAutoCache == true) { // 象征性获得一个日志文件的尺寸,主要目的是为了触发一次通道登录 // return: // -2 此类型的日志尚未启用 // -1 error // 0 file not found // 1 found nRet = GetFileSize( this.Stop, this.Channel, this.CacheDir, "20121001.log", this.LogType, out long lServerFileSize, out long lCacheFileSize, out strError); if (nRet == -1) { throw new ChannelException(this.Channel.ErrorCode, strError); } // 2015/11/25 if (nRet == -2) { yield break; // 此类型的日志尚未启用 } // 检查日志文件缓存目录的版本是否和当前用户的信息一致 // return: // -1 出错 // 0 一致 // 1 不一致 nRet = DetectCacheVersionFile( this.CacheDir, "version.xml", this.Channel.LibraryCodeList, this.Channel.Url, out strError); if (nRet == -1) { throw new Exception(strError); } if (nRet == 1) { REDO: // 清空当前缓存目录 nRet = DeleteDataDir( this.CacheDir, out strError); if (nRet == -1) { if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "清空当前缓存目录时发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") { throw new InterruptException(strError); } else if (e.ResultAction == "yes") { goto REDO; } else { } } else { throw new Exception(strError); } } #if NO if (nRet == -1) { throw new Exception(strError); } #endif TryCreateDir(this.CacheDir); // 重新创建目录 // 创建版本文件 nRet = CreateCacheVersionFile( this.CacheDir, "version.xml", this.Channel.LibraryCodeList, this.Channel.Url, out strError); if (nRet == -1) { throw new Exception(strError); } } } long lTotalSize = 0; List <string> lines = new List <string>(); // 经过处理后排除了不存在的文件名 List <string> ranges = new List <string>(); // 日期后面的偏移部分 List <long> sizes = new List <long>(); // 服务器日志文件的尺寸 #if NO this.Stop.SetMessage("正在准备获得日志文件尺寸 ..."); foreach (string strLine in this.FileNames) { // Application.DoEvents(); if (this.Stop != null && this.Stop.State != 0) { strError = "用户中断"; throw new InterruptException(strError); // yield break; ? } if (String.IsNullOrEmpty(strLine) == true) { continue; } string strFilename = strLine.Trim(); // 去掉注释 nRet = strFilename.IndexOf("#"); if (nRet != -1) { strFilename = strFilename.Substring(0, nRet).Trim(); } if (String.IsNullOrEmpty(strFilename) == true) { continue; } string strLogFilename = ""; string strRange = ""; nRet = strFilename.IndexOf(":"); if (nRet != -1) { strLogFilename = strFilename.Substring(0, nRet).Trim(); strRange = strFilename.Substring(nRet + 1).Trim(); } else { strLogFilename = strFilename.Trim(); strRange = ""; } if (strLogFilename.Length == 8) { strLogFilename += ".log"; } REDO_GETSIZE: long lServerFileSize = 0; long lCacheFileSize = 0; // 获得一个日志文件的尺寸 // -2 此类型的日志尚未启用 // -1 error // 0 file not found // 1 found nRet = GetFileSize( this.Stop, this.Channel, this.CacheDir, strLogFilename, this.LogType, out lServerFileSize, out lCacheFileSize, out strError); if (nRet == -1) { // throw new Exception(strError); if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "获取日志文件 " + strLogFilename + " 尺寸的操作发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") { throw new InterruptException(strError); } else if (e.ResultAction == "yes") { if (this.Stop != null) { this.Stop.Continue(); } goto REDO_GETSIZE; } else { // ?? continue; } } else { throw new ChannelException(this.Channel.ErrorCode, strError); } } if (nRet == 0) { continue; } if (lServerFileSize == 0) { continue; // 0字节的文件当作不存在处理 } // 2015/11/25 if (lServerFileSize == -1) { yield break; // 此类型的日志尚未启用 } Debug.Assert(lServerFileSize >= 0, ""); if (bAutoCache == true) { if (lCacheFileSize > 0) { lTotalSize += lCacheFileSize; } else { lTotalSize += lServerFileSize; } } else { lTotalSize += lServerFileSize; } // lines.Add(strFilename); lines.Add(strLogFilename); ranges.Add(strRange); // 记忆每个文件的尺寸,后面就不用获取了? sizes.Add(lServerFileSize); } #endif // 预先处理一下文件名 List <string> filenames = new List <string>(); foreach (string strLine in this.Dates) { if (this.Stop != null && this.Stop.State != 0) { strError = "用户中断"; throw new InterruptException(strError); } if (String.IsNullOrEmpty(strLine) == true) { continue; } string strFilename = strLine.Trim(); // 去掉注释 nRet = strFilename.IndexOf("#"); if (nRet != -1) { strFilename = strFilename.Substring(0, nRet).Trim(); } if (String.IsNullOrEmpty(strFilename) == true) { continue; } #if NO List <string> parts = StringUtil.ParseTwoPart(strFilename, ":"); string strRange = parts[1]; strFilename = parts[0].Substring(0, 8); if (string.IsNullOrEmpty(strRange) == false) { range_table[strFilename] = strRange; // TODO: 如何防范文件名重复? } #endif filenames.Add(strFilename); Debug.Assert(strFilename.Length >= 8, ""); } // 准备查找表 Hashtable length_table = new Hashtable(); { List <FileSize> size_pairs = GetFilesLength( // filenames ); foreach (FileSize size_pair in size_pairs) { length_table[size_pair.Date] = size_pair; } } foreach (string filename in filenames) { FileSize size_pair = length_table[filename.Substring(0, 8)] as FileSize; if (size_pair == null) { continue; } Debug.Assert(size_pair != null, ""); lines.Add(filename); sizes.Add(size_pair.ServerFileSize); if (size_pair.ServerFileSize == -1) { yield break; // 此类型的日志尚未启用 } Debug.Assert(size_pair.ServerFileSize >= 0, ""); if (bAutoCache == true) { if (size_pair.CacheFileSize > 0) { lTotalSize += size_pair.CacheFileSize; } else { lTotalSize += size_pair.ServerFileSize; } } else { lTotalSize += size_pair.ServerFileSize; } } long lDoneSize = 0; if (this.ProgressStart == -1) { lDoneSize = lTotalSize; } else { lDoneSize = this.ProgressStart; } lTotalSize += lDoneSize; if (this.Stop != null) { this.Stop.SetProgressRange(0, lTotalSize); } if (Estimate != null) { Estimate.SetRange(lDoneSize, lTotalSize); Estimate.StartEstimate(); } for (int i = 0; i < lines.Count; i++) { // Application.DoEvents(); if (this.Stop != null && this.Stop.State != 0) { strError = "用户中断"; throw new InterruptException(strError); // yield break; ? } string strLine = lines[i]; Debug.Assert(strLine.Length >= 8, ""); // string strRange = ranges[i]; // 2017/10/9 List <string> parts = StringUtil.ParseTwoPart(strLine, ":"); string strRange = parts[1]; strLine = parts[0]; string strLogFilename = strLine; #if NO string strLogFilename = ""; string strRange = ""; nRet = strLine.IndexOf(":"); if (nRet != -1) { strLogFilename = strLine.Substring(0, nRet).Trim(); strRange = strLine.Substring(nRet + 1).Trim(); } else { strLogFilename = strLine.Trim(); strRange = ""; } #endif { OperLogItemLoader loader = new OperLogItemLoader { Stop = this.Stop, Channel = this.Channel, // loader.owner = this.owner; Estimate = this.Estimate, Date = strLogFilename, Level = this.Level, ReplicationLevel = this.ReplicationLevel, lServerFileSize = sizes[i], Range = strRange, AutoCache = this.AutoCache, lProgressValue = lDoneSize, lSize = lTotalSize, Filter = this.Filter, LogType = this.LogType, ServerVersion = this.ServerVersion }; if (this.Prompt != null) { loader.Prompt += new MessagePromptEventHandler(loader_Prompt); } try { foreach (OperLogItem item in loader) { yield return(item); } } finally { if (this.Prompt != null) { loader.Prompt -= new MessagePromptEventHandler(loader_Prompt); } } lDoneSize = loader.lProgressValue; lTotalSize = loader.lSize; } } }
public IEnumerator GetEnumerator() { string strError = ""; int nRet = 0; long lRet = 0; if (this.Date.Length != 8) { throw new ArgumentException("FileName 成员值的长度应该是 8 字符"); } if ((this.LogType & LogType.AccessLog) != 0 && (this.LogType & LogType.OperLog) != 0) { throw new ArgumentException("OperLogItemLoader 的 LogType 只能使用一种类型"); } if (this.Stop != null && this.Estimate != null) { this.Stop.SetMessage("正在装入日志文件 " + this.Date + " 中的记录。" + "剩余时间 " + ProgressEstimate.Format(Estimate.Estimate(lProgressValue)) + " 已经过时间 " + ProgressEstimate.Format(Estimate.delta_passed)); } string strXml = ""; long lAttachmentTotalLength = 0; byte[] attachment_data = null; long lFileSize = 0; if (lServerFileSize == -1) { long _lServerFileSize = 0; string strStyle = "level-" + Level.ToString(); if ((this.LogType & LogType.AccessLog) != 0) { strStyle += ",accessLog"; } // 获得服务器端日志文件尺寸 lRet = this.Channel.GetOperLog( this.Stop, this.Date, -1, // lIndex, -1, // lHint, strStyle, "", // strFilter out strXml, out _lServerFileSize, 0, // lAttachmentFragmentStart, 0, // nAttachmentFramengLength, out attachment_data, out lAttachmentTotalLength, out strError); // 2015/11/25 if (lRet == -1) { throw new ChannelException(this.Channel.ErrorCode, strError); } this.lServerFileSize = _lServerFileSize; if (lRet == 0) { yield break; } // 2015/11/25 if (_lServerFileSize == -1) { yield break; // 此类型的日志尚未启用 } } Stream stream = null; bool bCacheFileExist = false; bool bRemoveCacheFile = false; // 是否要自动删除未全部完成的本地缓存文件 bool bAutoCache = this.AutoCache; if (bAutoCache == true) { string strFileName = this.Date; if ((this.LogType & LogType.AccessLog) != 0) { strFileName = this.Date + ".a"; } nRet = PrepareCacheFile( this.CacheDir, strFileName, // this.FileName, lServerFileSize, out bCacheFileExist, out stream, out strError); if (nRet == -1) { throw new Exception(strError); } if (bCacheFileExist == false && stream != null) { bRemoveCacheFile = true; } } try { if (bCacheFileExist == true) { lFileSize = stream.Length; } else { lFileSize = lServerFileSize; } // stop.SetProgressRange(0, lTotalSize); if (String.IsNullOrEmpty(Range) == true) { Range = "0-" + (long.MaxValue - 1).ToString(); // "0-9999999999"; } RangeList rl = new RangeList(Range); for (int i = 0; i < rl.Count; i++) { RangeItem ri = (RangeItem)rl[i]; // 让 100- 这样的 range 可以使用 if (ri.lLength == -1) { ri.lLength = long.MaxValue - ri.lStart; } OperLogInfo[] records = null; long lStartRecords = 0; long lHint = -1; long lHintNext = -1; for (long lIndex = ri.lStart; lIndex < ri.lStart + ri.lLength; lIndex++) { // Application.DoEvents(); if (this.Stop != null && this.Stop.State != 0) { strError = "用户中断"; throw new InterruptException(strError); // yield break; ? } if (lIndex == ri.lStart) { lHint = -1; } else { lHint = lHintNext; } if (bCacheFileExist == true) { if (lHint == -1) { // return: // -1 error // 0 成功 // 1 到达文件末尾或者超出 nRet = LocationRecord(stream, lIndex, out strError); if (nRet == -1) { throw new Exception(strError); } } else { // 根据暗示找到 if (lHint == stream.Length) { break; } if (lHint > stream.Length) { strError = "lHint参数值不正确"; throw new Exception(strError); } if (stream.Position != lHint) { stream.Seek(lHint, SeekOrigin.Begin); } } nRet = ReadCachedEnventLog( stream, out strXml, out lAttachmentTotalLength, out strError); if (nRet == -1) { throw new Exception(strError); } lHintNext = stream.Position; } else { if (records == null || lIndex /*- ri.lStart*/ >= lStartRecords + records.Length) { int nCount = -1; if (ri.lLength >= Int32.MaxValue) { nCount = -1; // 500; // -1; } else { nCount = (int)ri.lLength; // Math.Min(500, (int)ri.lLength); } string strStyle = "level-" + Level.ToString(); if ((this.LogType & LogType.AccessLog) != 0) { strStyle += ",accessLog"; } // 2017/10/9 if (this.ReplicationLevel == true) { strStyle += ",supervisor"; // 注:当前账户中还应该包含 replicatoin 权限才能真正获得日志记录中的密码字段 } if (string.IsNullOrEmpty(this.ServerVersion) == false && StringUtil.CompareVersion(this.ServerVersion, "3.17") >= 0) { strStyle += ",wait"; } REDO: // 获得日志 // return: // -1 error // 0 file not found // 1 succeed // 2 超过范围,本次调用无效 lRet = this.Channel.GetOperLogs( this.Stop, this.Date + ".log", lIndex, lHint, nCount, strStyle, this.Filter, // strFilter out records, out strError); if (lRet == -1) { #if NO DialogResult result = MessageBox.Show(owner, "获取日志信息 (" + this.FileName + " " + lIndex.ToString() + ") 的操作发生错误: " + strError + "\r\n\r\n是否重试操作?\r\n\r\n(是: 重试; 否: 跳过本次操作,继续后面的操作; 放弃: 停止全部操作)", "OperLogItemLoader", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); if (result == DialogResult.Yes) { goto REDO; } if (result == DialogResult.Cancel) { throw new Exception(strError); } else { // TODO: 是否要在listview中装入一条表示出错的行? lHintNext = -1; continue; } #endif if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = "获取 " + this._logType.ToString() + " 日志信息 (" + this.Date + " " + lIndex.ToString() + ") 的操作发生错误: " + strError; e.Actions = "yes,no,cancel"; this.Prompt(this, e); if (e.ResultAction == "cancel") { throw new InterruptException(strError); } else if (e.ResultAction == "yes") { if (this.Stop != null) { this.Stop.Continue(); } goto REDO; } else { lHintNext = -1; continue; } } else { throw new ChannelException(this.Channel.ErrorCode, strError); } } if (lRet == 0) { yield break; } if (lRet == 2) { break; } // records数组表示的起点位置 lStartRecords = lIndex /* - ri.lStart*/; } OperLogInfo info = records[lIndex - lStartRecords]; strXml = info.Xml; lHintNext = info.HintNext; lAttachmentTotalLength = info.AttachmentLength; // 写入本地缓存的日志文件 if (stream != null) { try { WriteCachedEnventLog( stream, strXml, lAttachmentTotalLength); } catch (Exception ex) { strError = "写入本地缓存文件的时候出错: " + ex.Message; throw new Exception(strError); } } } #if NO // 2011/12/30 // 日志记录可能动态地增加了,超过了原先为ProgressBar设置的范围 if (lFizeTotalSize < (int)lHintNext) { lFizeTotalSize = lHintNext; stop.SetProgressRange(0, lFizeTotalSize); } #endif if (lHintNext >= 0) { // 校正 if (lProgressValue + lHintNext >= lSize) // > 2017/12/4 修改为 >= { lSize = lProgressValue + lHintNext; if (this.Stop != null) { this.Stop.SetProgressRange(0, lSize); } if (this.Estimate != null) { Estimate.SetRange(0, lSize); } } this.Stop?.SetProgressValue(lProgressValue + lHintNext); } if (lIndex % 100 == 0) { if (this.Stop != null && this.Estimate != null) { Estimate.Text = "剩余时间 " + ProgressEstimate.Format(Estimate.Estimate(lProgressValue + lHintNext)) + " 已经过时间 " + ProgressEstimate.Format(Estimate.delta_passed); this.Stop.SetMessage("正在装入日志文件 " + this.Date + " 中的记录 " + lIndex.ToString() + " 。" + Estimate.Text); } } { OperLogItem item = new OperLogItem { Xml = strXml, Index = lIndex, Date = this.Date.Substring(0, 8), AttachmentLength = lAttachmentTotalLength }; yield return(item); } } } // 创建本地缓存的日志文件的 metadata 文件 if (bCacheFileExist == false && stream != null) { string strFileName = this.Date; if ((this.LogType & LogType.AccessLog) != 0) { strFileName = this.Date + ".a"; } nRet = CreateCacheMetadataFile( this.CacheDir, strFileName, // this.FileName, lServerFileSize, out strError); if (nRet == -1) { throw new Exception(strError); } } bRemoveCacheFile = false; // 不删除 } finally { if (stream != null) { stream.Close(); } if (bRemoveCacheFile == true) { string strFileName = this.Date; if ((this.LogType & LogType.AccessLog) != 0) { strFileName = this.Date + ".a"; } string strError1 = ""; nRet = DeleteCacheFile( this.CacheDir, strFileName, // this.FileName, out strError1); if (nRet == -1) { // MessageBox.Show(owner, strError1); if (this.Prompt != null) { MessagePromptEventArgs e = new MessagePromptEventArgs(); e.MessageText = strError1; e.Actions = "ok"; this.Prompt(this, e); } } } } lProgressValue += lFileSize; }