private void ApplySessionSelection() { foreach (ListViewItem item in sessionListView.Items) { Reader.Session ses = (Reader.Session)item.Tag; ses.Visible = item.Checked; } }
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; TLevel = threadInfo.TLevel; 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]; }
private void sessionCombo_SelectedIndexChanged(object sender, EventArgs e) { Reader.Session session = (Reader.Session)sessionCombo.SelectedItem; long sessionSize = 0; double sessionPercent = 0; lock (SessionObjects.Lock) { if (session == SessionObjects.AllSessionObjects.Last()) { sessionSize = _reader.InitialSize - session.SessionStartPos; } else { Reader.Session nextSession = SessionObjects.AllSessionObjects[session.Index + 1]; sessionSize = nextSession.SessionStartPos - session.SessionStartPos; } } sessionPercent = (double)sessionSize / (double)_reader.InitialSize; string sizeMsg = string.Format("{0:N0} ({1:P1} of file)", sessionSize, sessionPercent); sessionListView.Items.Clear(); sessionListView.Items.Add(new ListViewItem(new string[] { "Creation time (UTC)", session.CreationTimeUtc.ToString() + " UTC" })); sessionListView.Items.Add(new ListViewItem(new string[] { "Creation time (logger's TZ)", session.CreationTimeLoggersTZ.ToString() + " " + session.LoggersTimeZone })); sessionListView.Items.Add(new ListViewItem(new string[] { "Creation time (local TZ)", ToLocalTZ(session.CreationTimeUtc) })); sessionListView.Items.Add(new ListViewItem(new string[] { "Last timestamp", ToLocalTZ(session.LastRecordTimeUtc) })); sessionListView.Items.Add(new ListViewItem(new string[] { "Elapsed time", (session.LastRecordTimeUtc - session.CreationTimeUtc).ToString() })); sessionListView.Items.Add(new ListViewItem(new string[] { "Circular logging started", session.InCircularPart.ToString() })); sessionListView.Items.Add(new ListViewItem(new string[] { "Last record number", session.LastRecordNum.ToString("N0") })); sessionListView.Items.Add(new ListViewItem(new string[] { "Record count", session.RecordsRead.ToString("N0") })); sessionListView.Items.Add(new ListViewItem(new string[] { "Records lost by wrapping", (session.LastRecordNum - session.RecordsRead).ToString("N0") })); sessionListView.Items.Add(new ListViewItem(new string[] { "Max session size (KB)", session.MaxKb.ToString("N0") })); sessionListView.Items.Add(new ListViewItem(new string[] { "Session size (bytes)", sizeMsg })); sessionListView.Items.Add(new ListViewItem(new string[] { "Loggers assembly version", session.LoggersAssemblyVersion })); sessionListView.Items.Add(new ListViewItem(new string[] { "GUID", session.FileGuid.ToString() })); sessionNameCol.AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent); sessionValueCol.AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent); }
// This constructs a missing MethodEntry Record from the given ReaderStackEntry. // This is for MethodEntry records lost due to wrapping. public Record(ReaderThreadInfo threadInfo, ExplicitStackEntry methodEntry, Reader.Session session) { IsEntry = true; //IsExit = false; MsgNum = 0; // TBD Time = DateTime.MinValue; // TBD Index = 0; // TBD Thread = threadInfo.Thread; ThreadName = threadInfo.ThreadName; TLevel = methodEntry.TLevel; Logger = methodEntry.Logger; StackDepth = methodEntry.Depth; MethodName = methodEntry.Method; Lines = new string[] { string.Format("{{{0}: entered (replaces record lost due to wrapping)", MethodName.Name) }; Session = session; // 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]; }
// This generates replacements for missing entry/exit records that were lost when // the log wrapped, but whose counterparts were not lost. // Called when we read the first line for this thread in the circular part of the log. // The thread's true call stack (logged with each thread's first record in each block) // was just read from the log and is passed via the actualStack parameter. internal void MakeMissingRecords(ExplicitStackEntry[] actualStack, List <Record> generatedRecs, Reader.Session session) { // We only do this once per thread, for the first record in the circular log for each // thread. If MissingEntryRecords is not null, we already did it. if (!_missingRecsGenerated) { _missingRecsGenerated = true; var MissingEntryRecords = new List <Record>(); // StackTop is the "top" entry in the stack determined by // pushing MethodEntry records and then popping // them off when MethodExit records are found in the log. // That stack becomes inaccurate // due to records being lost when the log wraps. // However, the true stack for this thread was explicitly // recorded in the circular part of the log and has now been // passed to this method as actualStack. // By comparing the items in the two stacks, we can generate // the missing MethodEntry records (for items that are in // actualStack but not in the StackTop stack) and the missing // MethodExit records (for items that are in the StackTop stack // but not the actualStack). We also "fix" the StackTop stack. // this.Depth was set to actualStack.Length before this method was called. // If this.Depth is 0, actualStack is null. // The top stack entry comes first in actualStack. int actualStackIndex = 0; // The key property of each stack entry is the line number where // each method call starts in the log. For example, suppose the StackTop // stack and the actualStack contain entries with the // following line numbers. // // StackTop: 400 300 200 100 // actualStack: 600 500 100 // // In the example, the StackTop calls at 400, 300, and 200 must have exited // in the lost part of the log (because they don't appear in actualStack), // so we generate MethodExit records to replace those that were lost. // We also pop the entries for 400, 300, and 200 off the StackTop stack. // // The calls at 600 and 500 occurred in the lost part of the log and have // not exited yet, so we generate MethodEntry records to replace those lost // records. We also push the generated MethodEntry records onto the // StackTop stack. // // The method call at line 100 occurred before the lost part of the log and // still has not exited (because it appears in both stacks). // // All the generated MethodExit records will be inserted before all the // generated MethodEntry records, and all pops must be done before all pushes. // We start at the top of each stack and loop until all entries are examined or // we find the point where both stacks match. while (StackTop != null || actualStackIndex < Depth) { // At least one of the stacks is not exhausted. if (StackTop == null) { // Only the actualStack has entries remaining, all of which represent // methods whose method entry records were lost. MissingEntryRecords.Add(new Record(this, actualStack[actualStackIndex], session)); ++actualStackIndex; } else if (actualStackIndex == Depth) { // Only the StackTop stack has entries remaining, all of which represent // methods whose exits were lost. generatedRecs.Add(new Record(StackTop)); Pop(); } else if (StackTop.MsgNum > actualStack[actualStackIndex].EntryLineNum) { generatedRecs.Add(new Record(StackTop)); Pop(); } else if (StackTop.MsgNum < actualStack[actualStackIndex].EntryLineNum) { MissingEntryRecords.Add(new Record(this, actualStack[actualStackIndex], session)); ++actualStackIndex; } else { // Once they are equal, all others will be equal. break; } } // Now do the Pushes for the generated entry records. MissingEntryRecords.Reverse(); foreach (Record entryRec in MissingEntryRecords) { entryRec.Caller = StackTop; Push(entryRec); } generatedRecs.AddRange(MissingEntryRecords); } }