Пример #1
0
        /// <summary>
        /// Get list of records bounded by specified start message filetime and message count
        /// </summary>
        /// <param name="StartFileTime">Starting message filetime</param>
        /// <param name="MessageCount"></param>
        /// <returns>List of Log Records</returns>
        public List<LogRecord> GetRecordsByStartFileTimeAndCount(ulong StartFileTime, int MessageCount = 1000)
        {
            log.DebugFormat("StartFileTime - {0}", StartFileTime);
            log.DebugFormat("MaximumMessageCount - {0}", MessageCount);

            List<LogRecord> returnValue = new List<LogRecord>();
            LogRecord localRecord = new LogRecord();

            //Find the exact message number and use the search by message number function
            localRecord = this.GetRecordByFileTime(StartFileTime, EarliestOrLatest.Latest);

            if (!localRecord.ReturnCode.Status)
            {
                log.WarnFormat("Can't locate a record considering filetime {0}", StartFileTime);
                return returnValue;
            }

            //Record retrieval was succesful
            return this.GetRecordsByStartMessageNumberAndCount(localRecord.MessageNumber, MessageCount);
        }
Пример #2
0
        /// <summary>
        /// Return a single log record identified by the specific message number.  If no record is found a blank log record is returned.
        /// </summary>
        /// <param name="MessageNumber">Specific message number to search for</param>
        /// <returns>A single log record</returns>
        public LogRecord GetRecordByMessageNumber(ulong MessageNumber)
        {
            log.DebugFormat("MessageNumber - {0}", MessageNumber);

            LogRecord returnValue = new LogRecord();

                /* For optimization purposes first locate the log files that may contain the specific message number
                 We say file(s) because there is currently an issue with how the log system writes files that may repeat a message number
                 in that case will find the first match and return that
                */
                 foreach(string logFilePath in GetLogFilePathsForMessageNumber(MessageNumber))
                 {
                     // Get a reference to the log file by opening it
                     if(!OpenLogFile(logFilePath).Status)
                     {
                         throw new aaLogReaderException(string.Format("Error opening log file {0}",logFilePath));
                     }

                     //Get the header which should be loaded into a global in memory now
                    LogHeader localHeader = this.CurrentLogHeader;

                    //Determine if we are closer to the beginning or end
                    if((MessageNumber  - localHeader.StartMsgNumber) <= (localHeader.EndMsgNumber - MessageNumber))
                    {
                        //Looks like we are closer to beginning to start at beginning and go next
                        returnValue = GetFirstRecord();

                        // Start looping until we find the record we are looking for
                        while(returnValue.ReturnCode.Status && returnValue.MessageNumber <MessageNumber )
                        {
                            returnValue = GetNextRecord();
                        }
                    }
                    else
                    {
                        //Looks like we are closer to the end so start at end and go previous
                        returnValue = GetLastRecord();

                        // Start looping until we find the record we are looking for
                        while (returnValue.ReturnCode.Status && returnValue.MessageNumber > MessageNumber)
                        {
                            returnValue = GetPrevRecord();
                        }
                    }

                    // Check to see if we have found our record
                    if(returnValue.MessageNumber == MessageNumber)
                    {
                        // Dump out of the for loop
                        break;
                    }
                 }

            return returnValue;
        }
Пример #3
0
        /// <summary>
        /// Get list of records bounded by the specified start and end message number
        /// </summary>
        /// <param name="StartMessageNumber">Specified starting message number</param>
        /// <param name="EndMessageNumber">Specified ending message number</param>        
        /// <returns>List of Log Records</returns>
        public List<LogRecord> GetRecordsByStartandEndMessageNumber(ulong StartMessageNumber, ulong EndMessageNumber)
        {
            log.DebugFormat("StartMessageNumber - {0}", StartMessageNumber);
            log.DebugFormat("EndMessageNumber - {0}", EndMessageNumber);

            List<LogRecord> returnValue = new List<LogRecord>();
            LogRecord localRecord = new LogRecord();

            if (StartMessageNumber > EndMessageNumber)
                {
                    // Reverse
                    log.WarnFormat("Start ({0}) and End ({0}) Message Numbers Reversed. Correcting before proceeding", StartMessageNumber, EndMessageNumber);
                    ulong temp = EndMessageNumber;
                    EndMessageNumber = StartMessageNumber;
                    StartMessageNumber = temp;
                }

                localRecord = this.GetRecordByMessageNumber(StartMessageNumber);

                if (localRecord.ReturnCode.Status)
                {
                    returnValue.Add(localRecord);
                }

                while ((localRecord.MessageNumber <= EndMessageNumber) && localRecord.ReturnCode.Status)
                {
                    localRecord = GetNextRecord();

                    if(localRecord.ReturnCode.Status)
                    {
                        returnValue.Add(localRecord);
                    }
                    else
                    {
                        break;
                    }
                }

            return returnValue;
        }
Пример #4
0
        /// <summary>
        /// Get the lastRecordRead immediately previous to the current lastRecordRead in the log file.  This call will swap to previous log files as required.
        /// </summary>
        /// <returns>A single log record</returns>
        public LogRecord GetPrevRecord()
        {
            log.Debug("");
            ulong LastMessageNumber;
            LogRecord localRecord = new LogRecord();

                if (this.LastRecordRead.OffsetToPrevRecord != 0)
                {
                    log.Debug("this.lastRecordRead.OffsetToPrevRecord != 0");

                    // Cache the last message number
                    LastMessageNumber = this.LastRecordRead.MessageNumber;

                    // Read the lastRecordRead based off offset information from last lastRecordRead read

                    localRecord = this.ReadLogRecord(this.LastRecordRead.OffsetToPrevRecord, Convert.ToUInt64(decimal.Subtract(new decimal(LastMessageNumber), decimal.One)));
                }
                // Check to see if we are at the beginning of if there is another log file we can connect to
                else if (System.String.Compare(this.CurrentLogHeader.PrevFileName, "", false) == 0)
                {
                    log.Debug("this.lastRecordRead.OffsetToPrevRecord = 0 AND this.logHeader.PrevFileName == 0");

                    localRecord.ReturnCode.Status = false;
                    // Beginning of Log
                    localRecord.ReturnCode.Message = "BOL";
                }
                else
                {
                    log.Debug("Close current log file");

                    // Close the currently opened log file
                    this._fileStream.Close();

                    string newPreviousLogFile = Path.Combine(this.GetLogDirectory(), this.CurrentLogHeader.PrevFileName);

                    log.Debug("newPreviousLogFile - " + newPreviousLogFile);

                    try
                    {
                        if (this.OpenLogFile(newPreviousLogFile).Status)
                        {
                            localRecord = this.GetLastRecord();
                            log.Debug("localRecord.ReturnCode.Status - " + localRecord.ReturnCode.Status);
                        }
                        else
                        {
                            log.ErrorFormat("Error attempting to open previous log file: {0}", newPreviousLogFile);
                        }
                    }
                    catch (Exception ex)
                    {
                        log.ErrorFormat("Error attempting to open previous log file: {0} - {1}", newPreviousLogFile, ex.Message);
                        throw new aaLogReaderException("Error attempting to open previous log file.", ex);
                    }
                }

            return localRecord;
        }
Пример #5
0
        /// <summary>
        ///  Return a single log record identified by the specific message filetime.  If no record is found a blank log record is returned.
        /// </summary>
        /// <param name="MessageFiletime">Message filetime to use when searching</param>
        /// <param name="TimestampEarlyOrLate">Earliest = Message immediately before timestamp, Latest = Message immediately after timestamp</param>
        /// <returns>A single log record</returns>
        public LogRecord GetRecordByFileTime(ulong MessageFiletime, EarliestOrLatest TimestampEarlyOrLate = EarliestOrLatest.Earliest)
        {
            log.DebugFormat("MessageFiletime - {0}", MessageFiletime);

            LogRecord returnValue = new LogRecord();
            bool foundRecord = false;

                /* For optimization purposes first locate the log files that may contain a message with the specified filetime
                 We say file(s) because there is currently an issue with how the log system writes files that may overlap timestamps
                 in that case will find the first match and return that
                 *
                 * General premise of searching early or late is that early will get message immediately on or before target timestamp
                 * and late will get message immediately on or after target timestamp
                */
                foreach (string logFilePath in GetLogFilePathsForMessageFileTime(MessageFiletime))
                {
                    // Get a reference to the log file by opening it
                    if (!OpenLogFile(logFilePath).Status)
                    {
                        throw new aaLogReaderException(string.Format("Error opening log file {0}", logFilePath));
                    }

                    //Get the header which should be loaded into a global in memory now
                    LogHeader localHeader = this.CurrentLogHeader;

                    //Determine if we are closer to the beginning or end
                    if ((MessageFiletime - localHeader.StartFileTime) <= (localHeader.EndFileTime - MessageFiletime))
                    {

                        log.DebugFormat("Starting from beginning of file at filetime {0}", localHeader.StartFileTime);

                        //Looks like we are closer to beginning to start at beginning and go next
                        returnValue = GetFirstRecord();

                        // Start looping until we find the record we are looking for considering the Early or Late Timestamp parameters
                        while (returnValue.ReturnCode.Status)
                        {
                            // If we have gone past our target timestamp then go back and get the last record
                            if (returnValue.EventFileTime >= MessageFiletime)
                            {
                                if (TimestampEarlyOrLate == EarliestOrLatest.Earliest)
                                {
                                    // Go back one record
                                    returnValue = GetPrevRecord();

                                    // Make sure we got a good record then dump out of the while loop
                                    if (returnValue.ReturnCode.Status)
                                    {
                                        foundRecord = true;
                                        break;
                                    }
                                }
                                else
                                {
                                    break;
                                }
                            }

                            // Get the next record
                            returnValue = GetNextRecord();
                        }
                    }
                    else
                    {
                        //Looks like we are closer to the end so start at end and go previous
                        returnValue = GetLastRecord();

                        // Start looping until we find the record we are looking for considering the Early or Late Timestamp parameters
                        while (returnValue.ReturnCode.Status)
                        {
                            // If we have gone past our target timestamp then go back and get the last record
                            if (returnValue.EventFileTime <= MessageFiletime)
                            {
                                if (TimestampEarlyOrLate == EarliestOrLatest.Latest)
                                {
                                    // Go back one record
                                    returnValue = GetNextRecord();

                                    // Make sure we got a good record then dump out of the while loop
                                    if (returnValue.ReturnCode.Status)
                                    {
                                        foundRecord = true;
                                        break;
                                    }
                                }
                                else
                                {
                                    break;
                                }
                            }

                            // Get the previous record
                            returnValue = GetPrevRecord();
                        }
                    }

                    // Check to see if we have found our record
                    if (foundRecord)
                    {
                        // Dump out of the for loop
                        break;
                    }
                }

            return returnValue;
        }
Пример #6
0
        /// <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;
        }
Пример #7
0
        /// <summary>
        /// Get the last lastRecordRead in the log as specified by the OffsetLastRecord in the header.
        /// </summary>
        /// <returns>A single log record</returns>
        public LogRecord GetLastRecord()
        {
            log.Debug("");
            LogRecord localRecord = new LogRecord();

            if (this.CurrentLogHeader.OffsetLastRecord == 0)
            {
                localRecord.ReturnCode.Status = false;
                localRecord.ReturnCode.Message = "Offset to Last Record is 0.  No record returned.";
            }
            else
            {
                localRecord = this.ReadLogRecord(this.CurrentLogHeader.OffsetLastRecord, this.CurrentLogHeader.EndMsgNumber);
            }

            return localRecord;
        }
Пример #8
0
        /// <summary>
        /// Get the first lastRecordRead in the log as specified by the OffsetFirstRecord in the header.
        /// </summary>
        /// <returns>A single log record</returns>
        public LogRecord GetFirstRecord()
        {
            log.Debug("");
            LogRecord localRecord = new LogRecord();

            if (this.CurrentLogHeader.OffsetFirstRecord == 0)
            {
                this.LastRecordRead = new LogRecord();
            }
            else
            {
                localRecord = this.ReadLogRecord(this.CurrentLogHeader.OffsetFirstRecord, this.CurrentLogHeader.StartMsgNumber);
            }

            return localRecord;
        }
Пример #9
0
        /// <summary>
        /// Calculate if the logic should get the next record based on multiple factors
        /// </summary>
        /// <param name="lastRecord">The last record retrieved</param>
        /// <param name="logRecordCount">Current number of records retrieved</param>
        /// <param name="lastReadMessageNumber">Message number indicating it should be the last message to retrieve</param>
        /// <param name="maximumMessages">Maximum number of messages to retrieve. Will be compared to logRecordCount</param>
        /// <param name="messagePatternToStop">A specific message pattern to indicate the logic should not retrieve the next record</param>
        /// <returns></returns>
        private bool ShouldGetNextRecord(LogRecord lastRecord,ulong logRecordCount, ulong lastReadMessageNumber, ulong maximumMessages, string messagePatternToStop)
        {
            bool returnValue = false;

            try
            {
                log.Debug("");
                log.Debug("lastReadMessageNumber - " + lastReadMessageNumber.ToString());
                log.Debug("maximumMessages - " + maximumMessages.ToString());
                log.Debug("messagePattern - " + messagePatternToStop);

                /* If the last retrieval was good
                * and we have an offset for previous lastRecordRead
                * and we haven't passed the maximum lastRecordRead count limit
                * retrieve the next previous lastRecordRead
                */
                returnValue = (lastRecord.ReturnCode.Status && (lastRecord.OffsetToNextRecord > 0) && (lastRecord.MessageNumber > (lastReadMessageNumber+1)) && (logRecordCount < maximumMessages));

                /* If the message pattern is not blank then apply a regex to see if we get a match
                 * If we match then that means this is the last lastRecordRead we should retrieve so return false
                 */
                if(returnValue && messagePatternToStop != "")
                {
                    returnValue &= !System.Text.RegularExpressions.Regex.IsMatch(lastRecord.Message, messagePatternToStop, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                }
            }
            catch(Exception ex)
            {
                log.Warn(ex);
                returnValue = false;
            }

            return returnValue;
        }
Пример #10
0
        /// <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;
        }
Пример #11
0
        private static LogRecord ReadLogRecord(Stream stream, int offset, int previousOffset, LogHeader header)
        {
            LOG.DebugFormat("offset: {0}", offset);
            // ReSharper disable once UseObjectOrCollectionInitializer
            var record = new LogRecord();
            record.RecordLength = stream.GetInt(offset + 4);
            record.OffsetToPrevRecord = previousOffset;
            record.OffsetToNextRecord = checked(offset + record.RecordLength);

            stream.Seek(offset, SeekOrigin.Begin);
            var bytes = new byte[record.RecordLength];
            stream.Read(bytes, 0, record.RecordLength);

            record.MessageNumber = bytes.GetULong(16);
            record.SessionID = string.Format("{0}.{1}.{2}.{3}", bytes[27], bytes[26], bytes[25], bytes[24]);
            record.ProcessID = (uint)bytes.GetInt(28);
            record.ThreadID = (uint)bytes.GetInt(32);
            record.EventFileTime = bytes.GetFileTime(36);

            var position = 44;
            int length;
            record.LogFlag = bytes.GetString(position, out length);

            position += length + 2;
            record.Component = bytes.GetString(position, out length);

            position += length + 2;
            record.Message = bytes.GetString(position, out length);

            position += length + 2;
            record.ProcessName = bytes.GetString(position, out length);
            return record;
        }
Пример #12
0
 public static string Header(char Delimiter = ',', ExportFormat format = ExportFormat.Full)
 {
     LogRecord lr = new LogRecord();
     return lr.localHeader(Delimiter, format);
 }
 public static string HeaderTSV(ExportFormat format = ExportFormat.Full)
 {
     return(LogRecord.Header('\t', format));
 }
        public static string Header(char Delimiter = ',', ExportFormat format = ExportFormat.Full)
        {
            LogRecord lr = new LogRecord();

            return(lr.localHeader(Delimiter, format));
        }