/// <summary> /// Read a log lastRecordRead that starts at the specified offset /// </summary> /// <param name="FileOffset">Offset for the current file stream</param> /// <param name="MessageNumber">Passed message number to set on the log lastRecordRead. This should be calculated from external logic</param> /// <returns>A single log record</returns> private LogRecord ReadLogRecord(int FileOffset, ulong MessageNumber = 0) { log.Debug(""); log.Debug("FileOffset - " + FileOffset.ToString()); log.Debug("MessageNumber - " + MessageNumber.ToString()); int recordLength = 0; LogRecord localRecord = new LogRecord(); byte[] byteArray = new byte[1]; int workingOffset = 0; int fieldLength; try { // Initialize the return status localRecord.ReturnCode.Status = false; localRecord.ReturnCode.Message = ""; // Initialize working position workingOffset = 0; // Check to make sure we can even read from the file if(!_fileStream.CanSeek) { throw new aaLogReaderException("Log file not open for reading"); } // Go to the spot in the file stream specified by the offset this._fileStream.Seek((long)FileOffset, SeekOrigin.Begin); // Make sure we have at least 8 byteArray of data to read before hitting the end byteArray = new byte[8]; if (this._fileStream.Read(byteArray, 0, 8) == 0) { throw new aaLogReaderException("Attempt to read past End-Of-Log-File"); } //Get the first 4 byteArray of data byte array that we just retrieved. // This tells us how long this lastRecordRead is. recordLength = BitConverter.ToInt32(byteArray, 4); // If the lastRecordRead length is not > 0 then bail on the function, returning an empty lastRecordRead with status code if(recordLength <= 0) { throw new aaLogReaderException("Record Length is 0"); } //Go back and reset to the specified offset this._fileStream.Seek((long)FileOffset, SeekOrigin.Begin); //Recreate the byte array with the proper length byteArray = new byte[checked(recordLength + 1)]; //Now get the actual lastRecordRead data into the byte array for processing this._fileStream.Read(byteArray, 0, recordLength); // Record Length. We've already calculated this so just use internal variable localRecord.RecordLength = recordLength; // Offset to Previous Record. localRecord.OffsetToPrevRecord = byteArray.GetInt(8); // Offset to Next Record localRecord.OffsetToNextRecord = checked((int)FileOffset + recordLength); // Session ID localRecord.SessionID = byteArray.GetSessionIDSegments(12).SessionID; //this._sessionSeg.SessionID; // Process ID localRecord.ProcessID = byteArray.GetUInt32(16); // Thread ID localRecord.ThreadID = byteArray.GetUInt32(20); // File Time localRecord.EventFileTime = byteArray.GetFileTime(24); // Log Flag workingOffset = 32; localRecord.LogFlag = byteArray.GetString(workingOffset, out fieldLength); /* * Calc new working offset based on length of previously retrieved field. * Can't forget that we're dealing with Unicode so we have to double the * length to find the proper byte offset */ workingOffset += fieldLength + 2; localRecord.Component = byteArray.GetString(workingOffset, out fieldLength); workingOffset += fieldLength + 2; localRecord.Message = byteArray.GetString(workingOffset, out fieldLength); workingOffset += fieldLength + 2; localRecord.ProcessName = byteArray.GetString(workingOffset, out fieldLength); // Get the host from the header information localRecord.HostFQDN = ReadLogHeader().HostFQDN; localRecord.ReturnCode.Status = true; localRecord.ReturnCode.Message = ""; // Set the message number on the lastRecordRead based on the value passed localRecord.MessageNumber = MessageNumber; } catch (System.ApplicationException saex) { // If this is a past the end of file message then handle gracefully if(saex.Message == "Attempt to read past End-Of-Log-File") { this.ReturnCloseValue = this.CloseCurrentLogFile(); // Re-init the lastRecordRead to make sure it's totally blank. Don't want to return a partial lastRecordRead localRecord = new LogRecord(); localRecord.ReturnCode.Status = false; localRecord.ReturnCode.Message = saex.Message; } else { throw; } } catch(Exception ex) { log.Error(ex); throw; } // Set the last lastRecordRead read to this one. this.LastRecordRead = localRecord; // Return the working lastRecordRead return localRecord; }
/// <summary> /// Write a text file out with metadata that can be used if the application is closed and reopened to read logs again /// </summary> /// <param name="CacheRecord">Complete record to write out containing cache information</param> private ReturnCodeStruct WriteStatusCacheFile(LogRecord CacheRecord) { log.Debug(""); log.Debug("CacheRecord - " + CacheRecord.ToJSON()); ReturnCodeStruct returnValue; try { System.IO.File.WriteAllText(this.GetStatusCacheFilePath(), CacheRecord.ToJSON()); returnValue = new ReturnCodeStruct { Status = true, Message = "" }; } catch(Exception ex) { log.Error(ex); returnValue = new ReturnCodeStruct { Status = false, Message = ex.Message}; } return returnValue; }
/// <summary> /// Read the log file header from the currently opened filestream /// </summary> /// <param name="logFileStream">Specific filestream to inspect and extract log header</param> /// <returns>The log header for the file stream</returns> public LogHeader ReadLogHeader(FileStream logFileStream) { log.DebugFormat("logFileStream length - ", logFileStream.Length); int readResult; LogHeader localHeader = new LogHeader(); int workingOffset = 0; byte[] byteArray = new byte[1]; int fieldLength; try { // Set our file pointer to the beginning logFileStream.Seek((long)0, SeekOrigin.Begin); //Recreate the Byte Array with the appropriate size byteArray = new byte[12]; //Get first 12 byteArray into the byte array. The header length is in the last 4 byteArray readResult = logFileStream.Read(byteArray, 0, 12); // Get the last4 byteArray, starting at byte 8 to get the length of the header int headerLength = BitConverter.ToInt32(byteArray, 8); logFileStream.Seek((long)0, SeekOrigin.Begin); // Redim the byte array to the size of the header byteArray = new byte[checked(headerLength + 1)]; //Now read in the entire header, considering the header length from above readResult = logFileStream.Read(byteArray, 0, headerLength); // Start to pick out the values // Start Message Number localHeader.StartMsgNumber = byteArray.GetULong(20); // Message Count localHeader.MsgCount = (ulong)byteArray.GetInt(28); // Start and End FileTime localHeader.StartFileTime = byteArray.GetFileTime(32); localHeader.EndFileTime = byteArray.GetFileTime(40); // Offset for the first lastRecordRead localHeader.OffsetFirstRecord = byteArray.GetInt(48); // Offset for the last lastRecordRead localHeader.OffsetLastRecord = byteArray.GetInt(52); // Computer Name workingOffset = 56; localHeader.ComputerName = byteArray.GetString(56, out fieldLength); // Session workingOffset += fieldLength + 2; localHeader.Session = byteArray.GetString(workingOffset, out fieldLength); // Previous File Name workingOffset += fieldLength + 2; localHeader.PrevFileName = byteArray.GetString(workingOffset, out fieldLength); //HostFQDN localHeader.HostFQDN = Fqdn.GetFqdn(); localHeader.ReturnCode = new ReturnCodeStruct { Status = true, Message = "" }; } catch (Exception ex) { this.ReturnCloseValue = this.CloseCurrentLogFile(); localHeader.ReturnCode = new ReturnCodeStruct { Status = false, Message = ex.Message }; log.Error(ex); } finally { // Set the log header to this locaheader we have calculated this.CurrentLogHeader = localHeader; } return this.CurrentLogHeader; }