private void ReadThreadID() { _threadId = _fileReader.ReadInt32() + _reader._maxThreadIDFromPrevSession; if (_threadId > MaxThreadID) { MaxThreadID = _threadId; } // Look up or add the entry for this ThreadId. if (!_reader._foundThreadIds.TryGetValue(_threadId, out _curThread)) { // First occurrence of this id. _curThread = new ReaderThreadInfo(); if (!_reader._oldThreadIds.TryGetValue(_threadId, out _curThread.Thread)) { _curThread.Thread = new ThreadObject(); } _curThread.Thread.Id = _threadId; lock (ThreadObjects.Lock) { ThreadObjects.AllThreadObjects.Add(_curThread.Thread); } _reader._foundThreadIds[_threadId] = _curThread; } }
public Record(DataFlags dataflags, ulong msgNum, DateTime time, ReaderThreadInfo threadInfo, Reader.Session session, string msg) { MsgNum = msgNum; Time = time; Thread = threadInfo.Thread; ThreadName = threadInfo.ThreadName; Level = threadInfo.Level; Logger = threadInfo.Logger; StackDepth = threadInfo.Depth; MethodName = threadInfo.MethodName; Caller = threadInfo.StackTop; Session = session; if ((dataflags & DataFlags.MethodEntry) != DataFlags.None) { // This is a method entry record. It always contains exactly one line of text. IsEntry = true; Lines = new string[] { string.Format("{{{0}: entered", MethodName.Name) }; } else if ((dataflags & DataFlags.MethodExit) != DataFlags.None) { // Method exit records always contain exactly one line of text. IsExit = true; Lines = new string[] { string.Format("}}{0}: exiting", MethodName.Name) }; } else { // The message text for this record may contain newlines. Split the // message into one or more lines. Lines = msg.Split(_splitArg); if (Lines.Length > 1) { // It's common for a carriage return to exist at the // end of each line. Remove them. for (int i = 0; i < Lines.Length; ++i) { Lines[i] = Lines[i].TrimEnd('\r'); } // It's common for the last line to be empty. If so, remove it. if (Lines.Last().Trim() == string.Empty) { Lines = Lines.Take(Lines.Length - 1).ToArray(); } } IsCollapsed = Lines.Length > 1 && !Settings.Default.ExpandNewlines; } // Each line also has a bool to indicate if it is bookmarked // and a row index it may map to. IsBookmarked = new bool[Lines.Length]; RowIndices = new int[Lines.Length]; }
public void CloseLogFile() { _fileReader.Close(); _fileReader = null; _curThread = null; _foundThreadIds = null; _foundThreadNames = null; _oldThreadNames = null; _oldThreadIds = null; _foundLoggers = null; _oldLoggers = null; }
// This constructs a missing MethodEntry Record from the given ReaderStackEntry. public Record(ReaderThreadInfo threadInfo, ReaderStackEntry methodEntry) { IsEntry = true; MsgNum = 0; // TBD Time = DateTime.MinValue; // TBD Index = 0; // TBD Thread = threadInfo.Thread; ThreadName = threadInfo.ThreadName; Level = methodEntry.Level; Logger = methodEntry.Logger; StackDepth = methodEntry.Depth; MethodName = methodEntry.Method; Lines = new string[] { string.Format("{{{0}: entered (replaces record lost due to wrapping)", MethodName) }; // Each record also has a bool to indicate if it is bookmarked // and a row index it may map to. IsBookmarked = new bool[1]; RowIndices = new int[1]; }
public Record ReadRecord() { // Read the DataFlags, then the data the Flags indicate is there. // Data must be read in the same order it was written (see FileLogging.WriteData). try { DataFlags flags = GetFlags(); if (flags == DataFlags.None) { return(null); } long startPos = _fileReader.BaseStream.Position; if ((flags & DataFlags.LineNumber) != DataFlags.None) { _recordNumber = _fileReader.ReadUInt32(); } else if (!InCircularPart) { ++_recordNumber; } else { // _recordNumber was incremented by GetFlags. } if ((flags & DataFlags.Time) != DataFlags.None) { _time = new DateTime(_fileReader.ReadInt64()); } if ((flags & DataFlags.ThreadId) != DataFlags.None) { _threadId = _fileReader.ReadInt32(); // Look up or add the entry for this ThreadId. if (!_foundThreadIds.TryGetValue(_threadId, out _curThread)) { // First occurrence of this id. _curThread = new ReaderThreadInfo(); if (!_oldThreadIds.TryGetValue(_threadId, out _curThread.Thread)) { _curThread.Thread = new ThreadObject(); } _curThread.Thread.Id = _threadId; ThreadObject.AllThreads.Add(_curThread.Thread); _foundThreadIds[_threadId] = _curThread; } } if ((flags & DataFlags.ThreadName) != DataFlags.None) { // A normal thread's name can only change from null to non-null. // ThreadPool threads can alternate between null and non-null. // If a thread's name changes from non-null to null, the logger // writes string.Empty for the thread name. string threadNameStr = _fileReader.ReadString(); if (threadNameStr == string.Empty) { _curThread.ThreadName = FindOrCreateThreadName("Thread " + _curThread.Thread.Id); } else { _curThread.ThreadName = FindOrCreateThreadName(threadNameStr); } } else if (_curThread.ThreadName == null) { _curThread.ThreadName = FindOrCreateThreadName("Thread " + _curThread.Thread.Id); } if ((flags & DataFlags.TraceLevel) != DataFlags.None) { _curThread.Level = (TracerX.TraceLevel)_fileReader.ReadByte(); LevelsFound |= _curThread.Level; } if (FormatVersion < 5) { if ((flags & DataFlags.StackDepth) != DataFlags.None) { _curThread.Depth = _fileReader.ReadByte(); } else if ((flags & DataFlags.MethodExit) != DataFlags.None) { --_curThread.Depth; } } else { if ((flags & DataFlags.StackDepth) != DataFlags.None) { _curThread.Depth = _fileReader.ReadByte(); if (InCircularPart) { if (_curThread.Depth > 0) { // In format version 5, we began logging each thread's current call // stack on the thread's first line in each block (i.e. when the // StackDepth flag is set). This is the thread's true call stack at // this point in the log. It reflects MethodEntry and MethodExit // records that may have been lost when the log wrapped (as well // as those that weren't lost). ReaderStackEntry[] trueStack = new ReaderStackEntry[_curThread.Depth]; for (int i = _curThread.Depth - 1; i >= 0; --i) { ReaderStackEntry entry = new ReaderStackEntry(); entry.EntryLineNum = _fileReader.ReadUInt32(); entry.Level = (TracerX.TraceLevel)_fileReader.ReadByte(); entry.Logger = GetLogger(_fileReader.ReadString()); entry.Method = _fileReader.ReadString(); entry.Depth = (byte)i; trueStack[i] = entry; } _curThread.MakeMissingRecords(trueStack); } else { _curThread.MakeMissingRecords(null); } } } // Starting in format version 5, the viewer decrements the depth on MethodExit // lines even if it was included on the line. if ((flags & DataFlags.MethodExit) != DataFlags.None) { --_curThread.Depth; } } if ((flags & DataFlags.LoggerName) != DataFlags.None) { string loggerName = _fileReader.ReadString(); _curThread.Logger = GetLogger(loggerName); } if ((flags & DataFlags.MethodName) != DataFlags.None) { _curThread.MethodName = _fileReader.ReadString(); } if ((flags & DataFlags.Message) != DataFlags.None) { _msg = _fileReader.ReadString(); } // Construct the Record before incrementing depth. Record record = new Record(flags, _recordNumber, _time, _curThread, _msg); if ((flags & DataFlags.MethodEntry) != DataFlags.None) { // Cause future records to be indented until a MethodExit is encountered. ++_curThread.Depth; // In format version 5+, we keep track of the call stack in the noncircular // part of the log by "pushing" MethodEntry records and "popping" MethodExit records if (FormatVersion >= 5 && !InCircularPart) { _curThread.Push(record); } } else if (FormatVersion >= 5 && !InCircularPart && (flags & DataFlags.MethodExit) != DataFlags.None) { _curThread.Pop(); } BytesRead += _fileReader.BaseStream.Position - startPos; if (InCircularPart && _fileReader.BaseStream.Position >= MaxMb << 20) { // We've read to the max file size in circular mode. Wrap. _fileReader.BaseStream.Position = _circularStartPos; } ++_recordsRead; return(record); } catch (Exception ex) { // The exception is either end-of-file or a corrupt file. // Either way, we're done. Returning null tells the caller to give up. return(null); } }