Example #1
0
        /// <summary>
        /// Initialises a new instance of the FieldLogExceptionItem class.
        /// </summary>
        /// <param name="priority">The priority of the new log item.</param>
        /// <param name="type">The scope type.</param>
        /// <param name="name">The scope name.</param>
        /// <param name="webRequestData">The web request data. This parameter is required for the WebRequestStart scope type.</param>
        public FieldLogScopeItem(FieldLogPriority priority, FieldLogScopeType type, string name, FieldLogWebRequestData webRequestData)
            : base(priority)
        {
            Type  = type;
            Level = FL.ScopeLevel;
            Name  = name;

            if (Type == FieldLogScopeType.ThreadStart)
            {
                IsBackgroundThread = Thread.CurrentThread.IsBackground;
                IsPoolThread       = Thread.CurrentThread.IsThreadPoolThread;

                Thread = Thread.CurrentThread;
            }
            if (Type == FieldLogScopeType.LogStart)
            {
                EnvironmentData = FieldLogEventEnvironment.Current();
                Size           += EnvironmentData.Size;
            }
            if (Type == FieldLogScopeType.WebRequestStart)
            {
                if (webRequestData == null)
                {
                    throw new ArgumentNullException("webRequestData", "The webRequestData parameter is required for the WebRequestStart scope type.");
                }
                WebRequestData = webRequestData;
                Size          += WebRequestData.Size;
            }

            Size += 4 + 4 +
                    (Name != null ? Name.Length * 2 : 0) +
                    4 + 4 + 4 + 4 + 4;
        }
Example #2
0
        /// <summary>
        /// Initialises a new instance of the FieldLogExceptionItem class.
        /// </summary>
        /// <param name="priority">The priority of the new log item.</param>
        /// <param name="ex">The exception instance.</param>
        /// <param name="context">The context in which the exception has been thrown. Can be an
        /// arbitrary string that is useful for the logging purpose.</param>
        /// <param name="customStackTrace">A StackTrace that shall be logged instead of the StackTrace from the Exception instance.</param>
        public FieldLogExceptionItem(FieldLogPriority priority, Exception ex, string context, StackTrace customStackTrace)
            : base(priority)
        {
            Exception = new FieldLogException(ex, customStackTrace);
            Context   = context;

            bool includeEnvironment = true;

            if (context == "AppDomain.FirstChanceException" ||
                context == FL.StackTraceOnlyExceptionContext)
            {
                // First-chance exception logging with environment may lead to crashes at WMI
                // requests, so it's disabled for now.
                // Testcase: Inspect FieldLogViewer with Snoop while debugging.
                includeEnvironment = false;
            }
            if (includeEnvironment)
            {
                EnvironmentData = FieldLogEventEnvironment.Current();
            }
            else
            {
                EnvironmentData = FieldLogEventEnvironment.Empty;
            }

            Size += Exception.Size +
                    (Context != null ? Context.Length * 2 : 0) +
                    EnvironmentData.Size;
        }
Example #3
0
        /// <summary>
        /// Initialises a new instance of the FieldLogDataItem class.
        /// </summary>
        /// <param name="priority">The priority of the new log item.</param>
        /// <param name="name">The name of the data item. Can be an arbitrary string that is useful for the logging purpose.</param>
        /// <param name="value">The value of the data item. Will be converted to a string. Line breaks are allowed for structuring.</param>
        public FieldLogDataItem(FieldLogPriority priority, string name, object value)
            : base(priority)
        {
            Name = name;
            Value = FormatValues(value);

            Size += (Name != null ? Name.Length * 2 : 0) +
                (Value != null ? Value.Length * 2 : 0);
        }
Example #4
0
        /// <summary>
        /// Initialises a new instance of the FieldLogTextItem class.
        /// </summary>
        /// <param name="priority">The priority of the new log item.</param>
        /// <param name="text">The text message.</param>
        /// <param name="details">Additional details of the log event.</param>
        public FieldLogTextItem(FieldLogPriority priority, string text, string details)
            : base(priority)
        {
            Text    = text;
            Details = details;

            Size += (Text != null ? Text.Length * 2 : 0) +
                    (Details != null ? Details.Length * 2 : 0);
        }
Example #5
0
        /// <summary>
        /// Initialises a new instance of the FieldLogDataItem class.
        /// </summary>
        /// <param name="priority">The priority of the new log item.</param>
        /// <param name="name">The name of the data item. Can be an arbitrary string that is useful for the logging purpose.</param>
        /// <param name="value">The value of the data item. Will be converted to a string. Line breaks are allowed for structuring.</param>
        public FieldLogDataItem(FieldLogPriority priority, string name, object value)
            : base(priority)
        {
            Name  = name;
            Value = FormatValues(value);

            Size += (Name != null ? Name.Length * 2 : 0) +
                    (Value != null ? Value.Length * 2 : 0);
        }
Example #6
0
 /// <summary>
 /// Appends more text to the details of the log item.
 /// </summary>
 /// <param name="priority">The new priority of the log item. This will only be changed if the priority is increased.</param>
 /// <param name="text">The text to append.</param>
 public void AppendDetails(FieldLogPriority priority, string text)
 {
     if (priority > Priority)
     {
         Priority = priority;
     }
     Details += (Details != null && !Details.EndsWith("\n") ? Environment.NewLine : "") +
                text;
     Size += text.Length * 2;
 }
        /// <summary>
        /// Initialises a new instance of the FieldLogFileGroupReader class. This sets up log
        /// readers for each priority and links additional readers for existing files to them.
        /// A FileSystemWatcher is set up to add new files as they are created.
        /// </summary>
        /// <param name="basePath">The path and file prefix of the log files to read.</param>
        /// <param name="singleFile">true to load a single file only. <paramref name="basePath"/>
        /// must be a full file name then.</param>
        /// <param name="readWaitHandle">The wait handle that will be signalled after all files
        /// have been read to the end and if the last reader is now going to wait for further data
        /// to be appended to the file.</param>
        public FieldLogFileGroupReader(string basePath, bool singleFile = false, EventWaitHandle readWaitHandle = null)
        {
            var prioValues = Enum.GetValues(typeof(FieldLogPriority));

            readTasks = new Task <bool> [prioValues.Length];

            if (!singleFile)
            {
                // Start file system watcher to detect new files
                string logDir  = Path.GetDirectoryName(basePath);
                string logFile = Path.GetFileName(basePath);
                fsw = new FileSystemWatcher(logDir, logFile + "-*.fl");
                fsw.NotifyFilter        = NotifyFilters.FileName;
                fsw.Created            += fsw_Created;
                fsw.EnableRaisingEvents = true;

                // Find all log files for every priority
                foreach (FieldLogPriority prio in prioValues)
                {
                    FindLogFiles(basePath, prio);
                }
            }
            else
            {
                Match m = Regex.Match(basePath, @"-([0-9])-[0-9]{18}\.fl");
                if (m.Success)
                {
                    FieldLogPriority prio = (FieldLogPriority)int.Parse(m.Groups[1].Value);
                    AddNewReader(prio, basePath, false);
                }
                else
                {
                    throw new ArgumentException("The file name cannot be analysed.");
                }
            }

            // Wait for all priorities to be read to the end, then signal one event
            if (readWaitHandle != null)
            {
                Task.Factory.StartNew(() => ReadWaitHandleTask(readWaitHandle));
            }

            waitForNewFilePrioTask = Task.Factory.StartNew <bool>(WaitForNewFilePrio);
            closeTask = Task.Factory.StartNew <bool>(WaitForClose);
        }
        /// <summary>
        /// Finds all currently existing log files and adds a new reader for each of them.
        /// </summary>
        /// <param name="basePath">The directory and file base name.</param>
        /// <param name="prio">The priority of files to find.</param>
        private void FindLogFiles(string basePath, FieldLogPriority prio)
        {
            lock (readerLock)
            {
                // Remove any files that were added from the FileSystemWatcher event before we
                // started scanning for files. Those files will now be found again anyway.
                readers[prio] = null;

                string        logDir    = Path.GetDirectoryName(basePath);
                string        logFile   = Path.GetFileName(basePath);
                List <string> fileNames = new List <string>(Directory.GetFiles(logDir, logFile + "-" + (int)prio + "-*.fl"));
                fileNames.Sort();
                foreach (string fileName in fileNames)
                {
                    AddNewReader(prio, fileName, false);
                }
            }
        }
        /// <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>
 /// Called when the FileSystemWatcher found a newly created file of the currently used
 /// log file set.
 /// </summary>
 /// <param name="sender">Unused.</param>
 /// <param name="args">Event arguments.</param>
 private void fsw_Created(object sender, FileSystemEventArgs args)
 {
     if (closeEvent.WaitOne(0))
     {
         return;                                      // Already closing...
     }
     // Ensure it's a file, not a directory
     if (File.Exists(args.FullPath))
     {
         lock (readerLock)
         {
             Match m = Regex.Match(args.FullPath, @"-([0-9])-[0-9]{18}\.fl");
             if (m.Success)
             {
                 FieldLogPriority prio = (FieldLogPriority)int.Parse(m.Groups[1].Value);
                 AddNewReader(prio, args.FullPath, true);
             }
         }
     }
 }
Example #11
0
        /// <summary>
        /// Initialises a new instance of the FieldLogItem class.
        /// </summary>
        /// <param name="priority">The priority of the new log item.</param>
        protected FieldLogItem(FieldLogPriority priority)
        {
            Time      = FL.UtcNow;
            Priority  = priority;
            SessionId = FL.SessionId;
            if (FL.ThreadId == 0)
            {
                FL.ThreadId = Thread.CurrentThread.ManagedThreadId;
            }
            ThreadId = FL.ThreadId;
#if ASPNET
            if (HttpContext.Current != null)
            {
                object value = HttpContext.Current.Items[FL.HttpContextKey_WebRequestId];
                if (value is uint)
                {
                    WebRequestId = (uint)value;
                }
            }
#endif

            Size = 4 + 4 + 8 + 4 + 16 + 4 + 4 + 4 + 4;
        }
Example #12
0
 /// <summary>
 /// Initialises a new instance of the FieldLogExceptionItem class.
 /// </summary>
 /// <param name="priority">The priority of the new log item.</param>
 /// <param name="type">The scope type.</param>
 /// <param name="name">The scope name.</param>
 public FieldLogScopeItem(FieldLogPriority priority, FieldLogScopeType type, string name)
     : this(priority, type, name, null)
 {
 }
Example #13
0
 /// <summary>
 /// Initialises a new instance of the FieldLogExceptionItem class.
 /// </summary>
 /// <param name="priority">The priority of the new log item.</param>
 /// <param name="ex">The exception instance.</param>
 /// <param name="context">The context in which the exception has been thrown. Can be an
 /// arbitrary string that is useful for the logging purpose.</param>
 public FieldLogExceptionItem(FieldLogPriority priority, Exception ex, string context)
     : this(priority, ex, context, null)
 {
 }
Example #14
0
 /// <summary>
 /// Initialises a new instance of the FieldLogExceptionItem class.
 /// </summary>
 /// <param name="priority">The priority of the new log item.</param>
 /// <param name="ex">The exception instance.</param>
 public FieldLogExceptionItem(FieldLogPriority priority, Exception ex)
     : this(priority, ex, null, null)
 {
 }
Example #15
0
 /// <summary>
 /// Initialises a new instance of the FieldLogExceptionItem class.
 /// </summary>
 /// <param name="priority">The priority of the new log item.</param>
 /// <param name="ex">The exception instance.</param>
 /// <param name="context">The context in which the exception has been thrown. Can be an
 /// arbitrary string that is useful for the logging purpose.</param>
 public FieldLogExceptionItem(FieldLogPriority priority, Exception ex, string context)
     : this(priority, ex, context, null)
 {
 }
Example #16
0
 /// <summary>
 /// Initialises a new instance of the FieldLogExceptionItem class.
 /// </summary>
 /// <param name="priority">The priority of the new log item.</param>
 /// <param name="ex">The exception instance.</param>
 public FieldLogExceptionItem(FieldLogPriority priority, Exception ex)
     : this(priority, ex, null, null)
 {
 }
Example #17
0
        /// <summary>
        /// Initialises a new instance of the FieldLogItem class.
        /// </summary>
        /// <param name="priority">The priority of the new log item.</param>
        protected FieldLogItem(FieldLogPriority priority)
        {
            Time = FL.UtcNow;
            Priority = priority;
            SessionId = FL.SessionId;
            if (FL.ThreadId == 0)
            {
                FL.ThreadId = Thread.CurrentThread.ManagedThreadId;
            }
            ThreadId = FL.ThreadId;
            #if ASPNET
            if (HttpContext.Current != null)
            {
                object value = HttpContext.Current.Items[FL.HttpContextKey_WebRequestId];
                if (value is uint)
                {
                    WebRequestId = (uint)value;
                }
            }
            #endif

            Size = 4 + 4 + 8 + 4 + 16 + 4 + 4 + 4 + 4;
        }
Example #18
0
        /// <summary>
        /// Initialises a new instance of the FieldLogExceptionItem class.
        /// </summary>
        /// <param name="priority">The priority of the new log item.</param>
        /// <param name="ex">The exception instance.</param>
        /// <param name="context">The context in which the exception has been thrown. Can be an
        /// arbitrary string that is useful for the logging purpose.</param>
        /// <param name="customStackTrace">A StackTrace that shall be logged instead of the StackTrace from the Exception instance.</param>
        public FieldLogExceptionItem(FieldLogPriority priority, Exception ex, string context, StackTrace customStackTrace)
            : base(priority)
        {
            Exception = new FieldLogException(ex, customStackTrace);
            Context = context;

            bool includeEnvironment = true;
            if (context == "AppDomain.FirstChanceException" ||
                context == FL.StackTraceOnlyExceptionContext)
            {
                // First-chance exception logging with environment may lead to crashes at WMI
                // requests, so it's disabled for now.
                // Testcase: Inspect FieldLogViewer with Snoop while debugging.
                includeEnvironment = false;
            }
            if (includeEnvironment)
            {
                EnvironmentData = FieldLogEventEnvironment.Current();
            }
            else
            {
                EnvironmentData = FieldLogEventEnvironment.Empty;
            }

            Size += Exception.Size +
                (Context != null ? Context.Length * 2 : 0) +
                EnvironmentData.Size;
        }
        /// <summary>
        /// Initialises a new instance of the <see cref="FieldLogFileWriter"/> class.
        /// </summary>
        /// <param name="fileName">The name of the log file to write to.</param>
        /// <param name="prio">The priority of the items in the log file.</param>
        public FieldLogFileWriter(string fileName, FieldLogPriority prio)
        {
            FileName = fileName;
            fileStream = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);

            //Match m = Regex.Match(fileName, "[^0-9]([0-9]{8}-[0-9]{6})[^0-9]");
            //if (m.Success)
            //{
            //    createdTime = DateTime.ParseExact(m.Groups[1].Value, "yyyyMMdd-HHmmss", CultureInfo.InvariantCulture);
            //}
            FileInfo fi = new FileInfo(fileName);
            createdTime = fi.CreationTimeUtc;

            try
            {
                // Setting the NTFS compression needs the file to be opened with FileAccess.ReadWrite
                int lpBytesReturned = 0;
                short COMPRESSION_FORMAT_DEFAULT = 1;
                int result = DeviceIoControl(fileStream.SafeFileHandle.DangerousGetHandle(),
                    FSCTL_SET_COMPRESSION, ref COMPRESSION_FORMAT_DEFAULT, 2 /*sizeof(short)*/,
                    IntPtr.Zero, 0, ref lpBytesReturned, IntPtr.Zero);
                int err = Marshal.GetLastWin32Error();
            }
            catch
            {
                // NTFS or Win32 may not be available
            }

            byte[] fileHeaderBytes = Encoding.UTF8.GetBytes(fileHeader);
            if (fileStream.Length == 0)
            {
                // Initialise file with header
                fileStream.Write(fileHeaderBytes, 0, fileHeaderBytes.Length);

                fileStream.WriteByte(FL.FileFormatVersion);   // File format version

                // Rewrite currently open scope items with RepeatedScope item type
                if (FL.LogScopeItem != null)
                {
                    if (FL.LogScopeItem.Priority == prio && FL.LogScopeItem.WasWritten)
                    {
                        FL.LogScopeItem.IsRepeated = true;
                        FL.LogScopeItem.Write(this);
                    }
                }
                foreach (FieldLogScopeItem item in new List<FieldLogScopeItem>(FL.ThreadScopes.Values))
                {
                    if (item.Priority == prio && item.WasWritten)
                    {
                        if (!item.Thread.IsAlive)
                        {
                            // Don't repeat dead threads
                            FL.ThreadScopes.Remove(item.ThreadId);
                            continue;
                        }
                        item.IsRepeated = true;
                        item.Write(this);
                    }
                }
                foreach (FieldLogScopeItem item in new List<FieldLogScopeItem>(FL.WebRequestScopes.Values))
                {
                    if (item.Priority == prio && item.WasWritten)
                    {
                        item.IsRepeated = true;
                        item.Write(this);
                    }
                }
                foreach (var stack in FL.CurrentScopes.Values)
                {
                    foreach (FieldLogScopeItem item in stack.ToArray())
                    {
                        if (item.Priority == prio && item.WasWritten)
                        {
                            item.IsRepeated = true;
                            item.Write(this);
                        }
                    }
                }
            }
            else
            {
                // Validate existing file
                byte[] bytes = new byte[fileHeaderBytes.Length];
                if (fileStream.Read(bytes, 0, fileHeaderBytes.Length) < fileHeaderBytes.Length)
                {
                    throw new FormatException("Invalid log file to append to. Header too short.");
                }
                for (int i = 0; i < fileHeaderBytes.Length; i++)
                    if (bytes[i] != fileHeaderBytes[i])
                        throw new FormatException("Invalid log file to append to. Wrong header.");

                int formatVersion = fileStream.ReadByte();
                if (formatVersion != FL.FileFormatVersion)
                {
                    throw new FormatException("Invalid log file to append to. Unsupported file format version (" + formatVersion + ").");
                }

                // Read existing texts into the cache to re-use them
                ReadTextCache();
            }

            // Append any new log items to the end of the file (just to be sure)
            fileStream.Seek(0, SeekOrigin.End);
        }
Example #20
0
 /// <summary>
 /// Initialises a new instance of the FieldLogTextItem class.
 /// </summary>
 /// <param name="priority">The priority of the new log item.</param>
 /// <param name="text">The text message.</param>
 public FieldLogTextItem(FieldLogPriority priority, string text)
     : this(priority, text, null)
 {
 }
        /// <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>
        /// Finds all currently existing log files and adds a new reader for each of them.
        /// </summary>
        /// <param name="basePath">The directory and file base name.</param>
        /// <param name="prio">The priority of files to find.</param>
        private void FindLogFiles(string basePath, FieldLogPriority prio)
        {
            lock (readerLock)
            {
                // Remove any files that were added from the FileSystemWatcher event before we
                // started scanning for files. Those files will now be found again anyway.
                readers[prio] = null;

                string logDir = Path.GetDirectoryName(basePath);
                string logFile = Path.GetFileName(basePath);
                List<string> fileNames = new List<string>(Directory.GetFiles(logDir, logFile + "-" + (int)prio + "-*.fl"));
                fileNames.Sort();
                foreach (string fileName in fileNames)
                {
                    AddNewReader(prio, fileName, false);
                }
            }
        }
Example #23
0
        /// <summary>
        /// Initialises a new instance of the FieldLogTextItem class.
        /// </summary>
        /// <param name="priority">The priority of the new log item.</param>
        /// <param name="text">The text message.</param>
        /// <param name="details">Additional details of the log event.</param>
        public FieldLogTextItem(FieldLogPriority priority, string text, string details)
            : base(priority)
        {
            Text = text;
            Details = details;

            Size += (Text != null ? Text.Length * 2 : 0) +
                (Details != null ? Details.Length * 2 : 0);
        }
 private bool ComparePriority(FieldLogPriority prio)
 {
     FieldLogPriority filterPrio;
     if (Enum.TryParse(Value, out filterPrio))
     {
         switch (Comparison)
         {
             case FilterComparison.Equals:
             case FilterComparison.NotEquals:
                 return prio == filterPrio;
             case FilterComparison.GreaterOrEqual:
                 return prio >= filterPrio;
             case FilterComparison.GreaterThan:
                 return prio > filterPrio;
             case FilterComparison.LessOrEqual:
                 return prio <= filterPrio;
             case FilterComparison.LessThan:
                 return prio < filterPrio;
             default:
                 throw new Exception("Invalid comparison for Priority column: " + Comparison);
         }
     }
     else
     {
         // Invalid value for Priority column
         return false;
     }
 }
Example #25
0
 /// <summary>
 /// Initialises a new instance of the FieldLogExceptionItem class.
 /// </summary>
 /// <param name="priority">The priority of the new log item.</param>
 /// <param name="type">The scope type.</param>
 /// <param name="name">The scope name.</param>
 public FieldLogScopeItem(FieldLogPriority priority, FieldLogScopeType type, string name)
     : this(priority, type, name, null)
 {
 }
        /// <summary>
        /// Reads the next log item from the log file group. If all files have been read until the
        /// end, this method blocks until a new log item was written to any file, or until the
        /// close event was set.
        /// </summary>
        /// <returns>The next log item, or null if there are no more log items and the waiting was cancelled.</returns>
        public FieldLogItem ReadLogItem()
        {
            while (true)
            {
                Task <bool>[] availableTasks;
                lock (readerLock)
                {
                    availableTasks = readTasks
                                     .Where(t => t != null)
                                     .Concat(new Task <bool>[] { waitForNewFilePrioTask })
                                     .Concat(new Task <bool>[] { closeTask })
                                     .ToArray();
                }
                Task.WaitAny(availableTasks);
                // We don't care about which task has finished. It may actually be multiple tasks.
                // We just test them all and use the result of all tasks that have finished.
                // Compare all completed readers' current value, find the smallest time and move
                // that enumerator one further.
                DateTime         minTime     = DateTime.MaxValue;
                FieldLogItem     minTimeItem = null;
                FieldLogPriority minTimePrio = 0;
                foreach (var availableTask in availableTasks)
                {
                    if (availableTask.IsCompleted)
                    {
                        // Search from the lowest priority up, as lower priorities appear more often
                        for (int prioInt = 0; prioInt < readTasks.Length; prioInt++)
                        {
                            if (availableTask == readTasks[prioInt])
                            {
                                // A reader enumerator task has finished, consider its result
                                FieldLogPriority prio = (FieldLogPriority)prioInt;
                                if (availableTask.Result)
                                {
                                    // A new item of this priority is available.
                                    // Fetch the item from the reader.
                                    FieldLogItem item = readers[prio].Current;
                                    if (item.Time < minTime)
                                    {
                                        // The item's time is before any other item in this run, remember it
                                        minTime     = item.Time;
                                        minTimeItem = item;
                                        minTimePrio = prio;
                                    }
                                }
                                else
                                {
                                    // This priority's reader has finished, remove it.
                                    // Lock so that AddNewReader won't mess up if it finds a new file for this priority.
                                    lock (readerLock)
                                    {
                                        readers[prio].Dispose();
                                        readers[prio]      = null;
                                        readTasks[prioInt] = null;
                                    }
                                }
                            }
                        }
                        if (availableTask == waitForNewFilePrioTask)
                        {
                            // A file of a new priority was added and the WaitAny was interrupted,
                            // to restart with the newly added reader added to the list of
                            // available tasks.
                            // Recreate the signal task and continue.
                            waitForNewFilePrioTask = Task <bool> .Factory.StartNew(WaitForNewFilePrio);
                        }
                        if (availableTask == closeTask)
                        {
                            // The reader was requested to close.
                            // Close all current enumerators, which then close all readers and
                            // everything should tidy up itself...
                            if (fsw != null)
                            {
                                fsw.EnableRaisingEvents = false;
                                fsw.Dispose();
                            }
                            foreach (var reader in readers.Values)
                            {
                                if (reader != null)
                                {
                                    reader.Close();
                                }
                            }
                            return(null);
                        }
                    }
                }
                if (minTimeItem != null)
                {
                    // We found an item.
                    // Create new task for the next item of this priority
                    var task = Task <bool> .Factory.StartNew(readers[minTimePrio].MoveNext);

                    readTasks[(int)minTimePrio] = task;
                    // Now return the next log item in time of all that are currently available
                    return(minTimeItem);
                }
                // Restart this loop and wait for the next event
            }
        }
Example #27
0
        /// <summary>
        /// Initialises a new instance of the FieldLogExceptionItem class.
        /// </summary>
        /// <param name="priority">The priority of the new log item.</param>
        /// <param name="type">The scope type.</param>
        /// <param name="name">The scope name.</param>
        /// <param name="webRequestData">The web request data. This parameter is required for the WebRequestStart scope type.</param>
        public FieldLogScopeItem(FieldLogPriority priority, FieldLogScopeType type, string name, FieldLogWebRequestData webRequestData)
            : base(priority)
        {
            Type = type;
            Level = FL.ScopeLevel;
            Name = name;

            if (Type == FieldLogScopeType.ThreadStart)
            {
                IsBackgroundThread = Thread.CurrentThread.IsBackground;
                IsPoolThread = Thread.CurrentThread.IsThreadPoolThread;

                Thread = Thread.CurrentThread;
            }
            if (Type == FieldLogScopeType.LogStart)
            {
                EnvironmentData = FieldLogEventEnvironment.Current();
                Size += EnvironmentData.Size;
            }
            if (Type == FieldLogScopeType.WebRequestStart)
            {
                if (webRequestData == null) throw new ArgumentNullException("webRequestData", "The webRequestData parameter is required for the WebRequestStart scope type.");
                WebRequestData = webRequestData;
                Size += WebRequestData.Size;
            }

            Size += 4 + 4 +
                (Name != null ? Name.Length * 2 : 0) +
                4 + 4 + 4 + 4 + 4;
        }
        /// <summary>
        /// Initialises a new instance of the <see cref="FieldLogFileWriter"/> class.
        /// </summary>
        /// <param name="fileName">The name of the log file to write to.</param>
        /// <param name="prio">The priority of the items in the log file.</param>
        public FieldLogFileWriter(string fileName, FieldLogPriority prio)
        {
            FileName   = fileName;
            fileStream = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);

            //Match m = Regex.Match(fileName, "[^0-9]([0-9]{8}-[0-9]{6})[^0-9]");
            //if (m.Success)
            //{
            //    createdTime = DateTime.ParseExact(m.Groups[1].Value, "yyyyMMdd-HHmmss", CultureInfo.InvariantCulture);
            //}
            FileInfo fi = new FileInfo(fileName);

            createdTime = fi.CreationTimeUtc;

            try
            {
                // Setting the NTFS compression needs the file to be opened with FileAccess.ReadWrite
                int   lpBytesReturned            = 0;
                short COMPRESSION_FORMAT_DEFAULT = 1;
                int   result = DeviceIoControl(fileStream.SafeFileHandle.DangerousGetHandle(),
                                               FSCTL_SET_COMPRESSION, ref COMPRESSION_FORMAT_DEFAULT, 2 /*sizeof(short)*/,
                                               IntPtr.Zero, 0, ref lpBytesReturned, IntPtr.Zero);
                int err = Marshal.GetLastWin32Error();
            }
            catch
            {
                // NTFS or Win32 may not be available
            }

            byte[] fileHeaderBytes = Encoding.UTF8.GetBytes(fileHeader);
            if (fileStream.Length == 0)
            {
                // Initialise file with header
                fileStream.Write(fileHeaderBytes, 0, fileHeaderBytes.Length);

                fileStream.WriteByte(FL.FileFormatVersion);                   // File format version

                // Rewrite currently open scope items with RepeatedScope item type
                if (FL.LogScopeItem != null)
                {
                    if (FL.LogScopeItem.Priority == prio && FL.LogScopeItem.WasWritten)
                    {
                        FL.LogScopeItem.IsRepeated = true;
                        FL.LogScopeItem.Write(this);
                    }
                }
                foreach (FieldLogScopeItem item in new List <FieldLogScopeItem>(FL.ThreadScopes.Values))
                {
                    if (item.Priority == prio && item.WasWritten)
                    {
                        if (!item.Thread.IsAlive)
                        {
                            // Don't repeat dead threads
                            FL.ThreadScopes.Remove(item.ThreadId);
                            continue;
                        }
                        item.IsRepeated = true;
                        item.Write(this);
                    }
                }
                foreach (FieldLogScopeItem item in new List <FieldLogScopeItem>(FL.WebRequestScopes.Values))
                {
                    if (item.Priority == prio && item.WasWritten)
                    {
                        item.IsRepeated = true;
                        item.Write(this);
                    }
                }
                foreach (var stack in FL.CurrentScopes.Values)
                {
                    foreach (FieldLogScopeItem item in stack.ToArray())
                    {
                        if (item.Priority == prio && item.WasWritten)
                        {
                            item.IsRepeated = true;
                            item.Write(this);
                        }
                    }
                }
            }
            else
            {
                // Validate existing file
                byte[] bytes = new byte[fileHeaderBytes.Length];
                if (fileStream.Read(bytes, 0, fileHeaderBytes.Length) < fileHeaderBytes.Length)
                {
                    throw new FormatException("Invalid log file to append to. Header too short.");
                }
                for (int i = 0; i < fileHeaderBytes.Length; i++)
                {
                    if (bytes[i] != fileHeaderBytes[i])
                    {
                        throw new FormatException("Invalid log file to append to. Wrong header.");
                    }
                }

                int formatVersion = fileStream.ReadByte();
                if (formatVersion != FL.FileFormatVersion)
                {
                    throw new FormatException("Invalid log file to append to. Unsupported file format version (" + formatVersion + ").");
                }

                // Read existing texts into the cache to re-use them
                ReadTextCache();
            }

            // Append any new log items to the end of the file (just to be sure)
            fileStream.Seek(0, SeekOrigin.End);
        }
 /// <summary>
 /// Logs an exception raised in the task. Call this like the ContinueWith method with the
 /// <see cref="TaskContinuationOptions.OnlyOnFaulted"/> option.
 /// </summary>
 /// <typeparam name="TResult">The type of the result produced by this Task.</typeparam>
 /// <param name="task"></param>
 /// <param name="prio">The priority of the log item.</param>
 /// <param name="taskName">The name of the task, used for the exception log item context.</param>
 /// <returns>A new continuation <see cref="Task"/>.</returns>
 public static Task LogFaulted <TResult>(this Task <TResult> task, FieldLogPriority prio, string taskName)
 {
     return(task.ContinueWith(t => FL.Exception(prio, t.Exception, taskName + " Task"), TaskContinuationOptions.OnlyOnFaulted));
 }
        private void WriteToFieldLog(string source, TraceEventType eventType, int id, string msg)
        {
            string shortMsg = null;

            // Name comparisons roughly in a descending order of frequency, to optimise performance
            if (source == PresentationTraceSources.DataBindingSource.Name)
            {
                HandleDataBindingMessage(id, ref msg, ref shortMsg);
            }
            else if (source == PresentationTraceSources.RoutedEventSource.Name)
            {
                if (id == 3)
                {
                    if (eventType == TraceEventType.Start)
                    {
                        eventType = TraceEventType.Verbose;                           // Don't indent for this
                    }
                    else if (eventType == TraceEventType.Stop)
                    {
                        return;                           // Don't log this
                    }
                }
                //if (id == 4)
                //{
                //    return;   // Don't log this
                //}
                HandleRoutedEventMessage(id, ref msg, ref shortMsg);
            }
            else if (source == PresentationTraceSources.ResourceDictionarySource.Name)
            {
                HandleResourceDictionaryMessage(id, ref msg, ref shortMsg);
            }
            else if (source == PresentationTraceSources.MarkupSource.Name)
            {
                HandleMarkupMessage(id, ref msg, ref shortMsg);
            }
            else if (source == PresentationTraceSources.AnimationSource.Name)
            {
                HandleAnimationMessage(id, ref msg, ref shortMsg);
            }
            else if (source == PresentationTraceSources.DependencyPropertySource.Name)
            {
                HandleDependencyPropertyMessage(id, ref msg, ref shortMsg);
            }
            else if (source == PresentationTraceSources.FreezableSource.Name)
            {
                if (id == 1)
                {
                    return;                       // Don't log this, it appears everywhere and comes from bugs in WPF
                }
                HandleFreezableMessage(id, ref msg, ref shortMsg);
            }
            else if (source == PresentationTraceSources.HwndHostSource.Name)
            {
                HandleHwndHostMessage(id, ref msg, ref shortMsg);
            }
            else if (source == PresentationTraceSources.NameScopeSource.Name)
            {
                HandleNameScopeMessage(id, ref msg, ref shortMsg);
            }
            else if (source == PresentationTraceSources.ShellSource.Name)
            {
                HandleShellMessage(id, ref msg, ref shortMsg);
            }
            // DocumentsSource does not have any information and is not augmented here

            // Fallback short message if unknown event ID
            if (shortMsg == null)
            {
                shortMsg = "ID " + id;
            }

            // Select appropriate FieldLog priority or otherwise highlight event type
            FieldLogPriority prio = FieldLogPriority.Trace;

            switch (eventType)
            {
            case TraceEventType.Critical:
            case TraceEventType.Error:
                prio = FieldLogPriority.Error;
                break;

            case TraceEventType.Warning:
                prio = FieldLogPriority.Warning;
                break;

            case TraceEventType.Information:
                prio = FieldLogPriority.Info;
                break;

            case TraceEventType.Start:
                //shortMsg += " [Start]";
                break;

            case TraceEventType.Stop:
                shortMsg += " [Stop]";
                break;

            case TraceEventType.Suspend:
                shortMsg += " [Suspend]";
                break;

            case TraceEventType.Resume:
                shortMsg += " [Resume]";
                break;

            case TraceEventType.Transfer:
                shortMsg += " [Transfer]";
                break;
            }

            // Write message to the log if it's still there
            if (!FL.IsShutdown)
            {
                if (eventType == TraceEventType.Stop)
                {
                    indentLevel--;
                }

                string indentPrefix = null;
                if (indentLevel < 0)
                {
                    indentPrefix = "«";
                    indentLevel  = 0;
                }
                else if (indentLevel > 0)
                {
                    // Use a cached pre-generated indent prefix for better performance
                    while (indentStrings.Count <= indentLevel)
                    {
                        int    newLevel = indentStrings.Count;
                        string prefix   = "";
                        for (int i = 1; i <= newLevel; i++)
                        {
                            prefix += "-  ";
                        }
                        indentStrings.Add(prefix);
                    }
                    indentPrefix = indentStrings[indentLevel];
                }

                FL.Text(
                    prio,
                    indentPrefix + shortName + ": " + shortMsg,
                    (!string.IsNullOrEmpty(msg) ? msg + "\n\n" : "") +
                    "Event ID: " + id + "\nEvent type: " + eventType + "\nSource: " + sourceName);

                if (eventType == TraceEventType.Start)
                {
                    indentLevel++;
                }
            }
        }
Example #31
0
 /// <summary>
 /// Initialises a new instance of the FieldLogTextItem class.
 /// </summary>
 /// <param name="priority">The priority of the new log item.</param>
 /// <param name="text">The text message.</param>
 public FieldLogTextItem(FieldLogPriority priority, string text)
     : this(priority, text, null)
 {
 }