/// <inheritdoc/> public override void WriteLine(string message) { msgSb.Append(message); var final = msgSb.ToString(); msgSb.Length = 0; if (!FL.IsShutdown) { FL.Trace(sourceName + ": " + final); } }
/// <summary> /// Creates a new log file reader and adds it to the priority's log file enumerator. /// </summary> /// <param name="prio">The priority of files to write.</param> /// <param name="fileName">The name of the log file.</param> /// <param name="fromFsw">Indicates whether the reader was created from a FileSystemWatcher event.</param> private void AddNewReader(FieldLogPriority prio, string fileName, bool fromFsw) { // Must be within a lock(readerLock)! FL.Trace("AddNewReader, prio=" + prio + ", fileName=" + Path.GetFileName(fileName) + ", fromFsw=" + fromFsw); // Reject the new file if it's already in the queue (delayed FSW event after active scan) if (readers.ContainsKey(prio) && readers[prio] != null && readers[prio].ContainsFile(fileName)) { // This file is already current or queued FL.Checkpoint("This file is already current or queued"); return; } var reader = new FieldLogFileReader(fileName, true); ManualResetEvent h; if (!prioReadSignals.TryGetValue(prio, out h)) { h = new ManualResetEvent(false); prioReadSignals[prio] = h; } reader.ReadWaitHandle = h; if (!readers.ContainsKey(prio) || readers[prio] == null) { // This is the first file of this priority readers[prio] = new FieldLogFileEnumerator(reader); readers[prio].Error += FieldLogFileEnumerator_Error; readTasks[(int)prio] = Task <bool> .Factory.StartNew(readers[prio].MoveNext); // Signal the blocking ReadLogItem method that there's a new reader now newFilePrioEvent.Set(); } else { // Chain the new reader after the last reader in the queue readers[prio].Append(reader, fromFsw); // TODO,DEBUG: What for? //newFilePrioEvent.Set(); } }
/// <summary> /// Advances the enumerator to the next log item of the currently read log file. If there /// are no more items in this file and there is a NextReader set, the first log item of the /// next file reader is selected. If there are no more items in this file and WaitMode is /// set, the method will block until another log item is appended to the current file or /// the wait operation is cancelled by a close event. /// </summary> /// <returns>true if the enumerator was successfully advanced to the next log item; /// false if the enumerator has passed the end of the collection.</returns> public bool MoveNext() { FieldLogFileReader nextReader = null; do { if (nextReader != null) { FL.Trace(reader.ItemCount + " items read from " + Path.GetFileName(reader.FileName)); reader = nextReader; FL.Trace("Switching to next reader " + Path.GetFileName(reader.FileName)); } try { item = reader.ReadLogItem(); } catch (Exception ex) { FL.Error(ex, "Reading item from log file"); OnError(ex); // Skip the rest of the current file and continue with the next one if // available. If this is the last file and WaitMode is set, this priority will // not be monitored anymore. item = null; } if (item == null && reader.IsClosing) { // Close event must have been set Dispose(); return(false); } nextReader = reader.NextReader; }while (item == null && nextReader != null); return(item != null); }
/// <summary> /// Appends a new FieldLogFileReader at the end of this enumerator. /// </summary> /// <param name="newReader">The new reader to append.</param> /// <param name="fromFsw">Indicates whether the reader was created from a FileSystemWatcher event.</param> public void Append(FieldLogFileReader newReader, bool fromFsw) { FieldLogFileReader currentLastReader = LastReader; currentLastReader.NextReader = newReader; // Unset wait mode for this reader, now that we know where to continue after this file if (fromFsw) { // The file is newly created. Take some time to actually start reading the previous // file before switching to this one. Once the first item has been read from the // file, more items will likely exist in the file, and the file is read until the // end. Then it will still sit there waiting for more items until the rest of this // delay has elapsed (which is not a big problem, if we get any items from that // file at all). #if NET20 new Thread(() => { Thread.Sleep(1000); currentLastReader.WaitMode = false; }).Start(); #else Task.Factory.StartNew(() => { Thread.Sleep(1000); currentLastReader.WaitMode = false; }); #endif } else { currentLastReader.WaitMode = false; } FL.Trace( "Appending next reader", "this=" + Path.GetFileName(currentLastReader.FileName) + "\nNext=" + Path.GetFileName(newReader.FileName) + "\nItems read from this=" + currentLastReader.ItemCount); }
/// <summary> /// Handles a custom time measurement timer for saving the time data. /// </summary> /// <param name="state">Unused.</param> private void OnCustomTimer(object state) { if (key == FL.EnsureJitTimerKey) { return; } long ticks, ticksPc, ticksTt, localCounter; lock (syncLock) { // Do nothing if the stopwatch was just started again or current data has already // been written if (stopwatch.IsRunning || !writePending) { return; } // Clear the flag while we're in the lock region writePending = false; // Fetch the data in the lock region localCounter = counter; // Subtract 4 ticks per measurement, determined by tests // TODO: 0-tick intervals have been observed many times. Is the correction needed at all? long correction = localCounter * 0; ticks = stopwatch.Elapsed.Ticks - correction; if (ticks < 0) { ticks = 0; } if (localCounter > 0) { ticksPc = ticks / localCounter; } else { ticksPc = 0; } long counterTt = localCounter - prevCounter; if (counterTt > 0) { ticksTt = (ticks - prevTicks) / counterTt; } else { ticksTt = 0; } prevTicks = ticks; prevCounter = localCounter; } // Total time // (Add 5 ticks for simple microseconds rounding) long roundTicks = ticks + 5; int seconds = (int)(roundTicks / 10000000); int ms = (int)((roundTicks % 10000000) / 10000); int us = (int)((roundTicks % 10000) / 10); // Per call, this time (since last item) long roundTicksTt = ticksTt + 5; int secondsTt = (int)(roundTicksTt / 10000000); int msTt = (int)((roundTicksTt % 10000000) / 10000); int usTt = (int)((roundTicksTt % 10000) / 10); // Per call time long roundTicksPc = ticksPc + 5; int secondsPc = (int)(roundTicksPc / 10000000); int msPc = (int)((roundTicksPc % 10000000) / 10000); int usPc = (int)((roundTicksPc % 10000) / 10); string text = "Custom timer " + key + " at " + localCounter; string details = localCounter + " calls\n" + secondsPc.ToString() + "." + msPc.ToString("000") + "\u2009" + usPc.ToString("000") + " seconds per call (" + ticksPc + " ticks)\n" + secondsTt.ToString() + "." + msTt.ToString("000") + "\u2009" + usTt.ToString("000") + " seconds per call since last item (" + ticksTt + " ticks)\n" + seconds.ToString() + "." + ms.ToString("000") + "\u2009" + us.ToString("000") + " seconds total (" + ticks + " ticks)"; FL.Trace(text, details); }