// Search down the stack for the next caller for the specified binary file.
        private string GetCaller(BinaryFileState fileData)
        {
            // For binary files, the stack depth is decremented AFTER this is called,
            // so check stackdepth > 1.
            if (fileData.StackDepth > 1)
            {
                for (StackEntry caller = TopStackEntry.Caller; caller != null; caller = caller.Caller)
                {
                    if (caller.BinaryFileState == fileData)
                    {
                        return(caller.MethodName);
                    }
                }

                Debug.Assert(false, "A caller should have been found.");
            }

            return("");
        }
        // Looks up the thread-specific state for the specified binary file,
        // creating a new one if necessary.
        internal BinaryFileState GetBinaryFileState(BinaryFile file)
        {
            BinaryFileState result = BinaryFileState;

            if (BinaryFileState == null || BinaryFileState.File != file)
            {
                // Look up or create the state data for the specified file.
                if (!_binaryFileStatesForThisThread.TryGetValue(file, out result))
                {
                    result      = new BinaryFileState();
                    result.File = file;
                    _binaryFileStatesForThisThread.Add(file, result);
                }

                BinaryFileState = result;
            }
            else
            {
                // We already have the data for the specified file.
            }

            return(result);
        }
Exemplo n.º 3
0
        // This sets bits in the flags parameter that specify what data to include with the line.
        private DataFlags SetDataFlags(DataFlags flags, ThreadData threadData, BinaryFileState fileThreadState, Logger logger, TraceLevel lineLevel)
        {
            if (_lastBlock != _curBlock)
            {
                // The very first line in each block (regardless of thread)
                // includes the time in case this line ends up being the first line due to wrapping.
                flags |= DataFlags.Time;

                if (CircularStarted)
                {
                    flags |= DataFlags.BlockStart;
                }
            }

            if (fileThreadState.LastBlock != _curBlock)
            {
                // First line in current block for the thread.  Include all per-thread data.
                flags |= DataFlags.StackDepth | DataFlags.MethodName | DataFlags.TraceLevel | DataFlags.ThreadId | DataFlags.LoggerName;

                if (threadData.Name != null)
                {
                    flags |= DataFlags.ThreadName;
                }
            }
            else
            {
                if (_lastThread != threadData)
                {
                    // This line's thread differs from the last line's thread.
                    flags |= DataFlags.ThreadId;
                }

                if (fileThreadState.LastThreadName != threadData.Name)
                {
                    // Thread's name has changed.
                    flags |= DataFlags.ThreadId | DataFlags.ThreadName;
                }

                if (fileThreadState.CurrentMethod != fileThreadState.LastMethod)
                {
                    // We have a new method name for this thread.
                    flags |= DataFlags.MethodName;
                }

                if (fileThreadState.LastTraceLevel != lineLevel)
                {
                    // This line's trace Level differs from the previous line
                    // logged by this thread.
                    flags |= DataFlags.TraceLevel;
                }

                if (fileThreadState.LastLogger != logger)
                {
                    // This line's logger name differs from the previous line
                    // logged by this thread.
                    flags |= DataFlags.LoggerName;
                }
            }

            return(flags);
        }
Exemplo n.º 4
0
        // This is what actually writes the output. The dataFlags parameter specifies what to write.
        private void WriteData(DataFlags dataFlags, ThreadData threadData, BinaryFileState fileThreadState, Logger logger, TraceLevel lineLevel, string msg)
        {
            ++_lineCnt;

            // Write the flags first so the viewer will know what else the record contains.
            _logfile.Write((ushort)dataFlags);

            if (CircularStarted)
            {
                _logfile.Write(_curBlock);

                if ((dataFlags & DataFlags.BlockStart) != DataFlags.None)
                {
                    // This will be the first record in the block.
                    // This stuff helps the viewer find the first chronological block
                    // even after wrapping.  Writting _lastBlockPosition forms a linked
                    // list of blocks that the viewer can follow.

                    //System.Diagnostics.Debug.Print("Block {0} starting at line {1}, position {2}", _curBlock, _lineCnt, _logfile.BaseStream.Position);
                    _logfile.Write(_lineCnt);
                    _logfile.Write(_lastBlockPosition);
                }
            }

            if ((dataFlags & DataFlags.Time) != DataFlags.None)
            {
                _logfile.Write(_curTime.Ticks);
            }

            if ((dataFlags & DataFlags.ThreadId) != DataFlags.None)
            {
                _logfile.Write(threadData.TracerXID);
            }

            if ((dataFlags & DataFlags.ThreadName) != DataFlags.None)
            {
                // ThreadPool thread names get reset to null when a thread is returned
                // to the pool and reused later.
                if (_hasPassword)
                {
                    _encryptor.Encrypt(threadData.Name ?? string.Empty);
                }
                else
                {
                    _logfile.Write(threadData.Name ?? string.Empty);
                }
            }

            if ((dataFlags & DataFlags.TraceLevel) != DataFlags.None)
            {
                _logfile.Write((byte)lineLevel);
            }

            // In format version 5 and later, the viewer subtracts 1 from the stack depth on
            // MethodExit lines instead of the logger, so just write the depth as-is.
            if ((dataFlags & DataFlags.StackDepth) != DataFlags.None)
            {
                _logfile.Write(fileThreadState.StackDepth);

                if (CircularStarted)
                {
                    // In the circular part, include the thread's call stack with the first line
                    // logged for each thread in each block.  This enables the viewer to
                    // regenerate method entry/exit lines lost due to wrapping.
                    // Added in format version 5.
                    int count = 0;
                    for (StackEntry stackEntry = threadData.TopStackEntry; stackEntry != null; stackEntry = stackEntry.Caller)
                    {
                        if (stackEntry.BinaryFileState == fileThreadState)
                        {
                            ++count;
                            _logfile.Write(stackEntry.EntryLine); // Changed to ulong in version 6.
                            _logfile.Write((byte)stackEntry.Level);

                            if (_hasPassword)
                            {
                                Debug.Assert(stackEntry.Logger.Name != null);
                                _encryptor.Encrypt(stackEntry.Logger.Name);

                                Debug.Assert(stackEntry.MethodName != null);
                                _encryptor.Encrypt(stackEntry.MethodName);
                            }
                            else
                            {
                                _logfile.Write(stackEntry.Logger.Name);
                                _logfile.Write(stackEntry.MethodName);
                            }
                        }
                    }

                    // The StackDepth we wrote previously is how the viewer will know how many
                    // stack entries to read.
                    System.Diagnostics.Debug.Assert(count == fileThreadState.StackDepth);
                }
            }

            if ((dataFlags & DataFlags.LoggerName) != DataFlags.None)
            {
                if (_hasPassword)
                {
                    _encryptor.Encrypt(logger.Name);
                }
                else
                {
                    _logfile.Write(logger.Name);
                }
            }

            if ((dataFlags & DataFlags.MethodName) != DataFlags.None)
            {
                if (_hasPassword)
                {
                    _encryptor.Encrypt(fileThreadState.CurrentMethod);
                }
                else
                {
                    _logfile.Write(fileThreadState.CurrentMethod);
                }

                fileThreadState.LastMethod = fileThreadState.CurrentMethod;
            }

            if ((dataFlags & DataFlags.Message) != DataFlags.None)
            {
                if (_hasPassword)
                {
                    _encryptor.Encrypt(msg ?? "");
                }
                else
                {
                    _logfile.Write(msg);
                }
            }

            _lastBlock  = _curBlock;
            _lastThread = threadData;
            fileThreadState.LastBlock      = _curBlock;
            fileThreadState.LastThreadName = threadData.Name;
            fileThreadState.LastTraceLevel = lineLevel;
            fileThreadState.LastLogger     = logger;
        }
Exemplo n.º 5
0
        // Determine what data needs to be written based on dataFlags,
        // whether circular logging has or should be started,
        // and whether we're starting a new circular block.
        // Write the output to the file.  Manage the circular part of the log.
        // Return the line number just written.
        private ulong WriteLine(DataFlags dataFlags, ThreadData threadData, Logger logger, TraceLevel lineLevel, DateTime explicitUtcTime, string msg, bool recursive)
        {
            BinaryFileState fileThreadState = threadData.GetBinaryFileState(this);

            lock (_fileLocker)
            {
                try
                {
                    if (IsOpen)
                    {
                        if (fileThreadState.LastFileNumber != CurrentFile)
                        {
                            // First time writing to this file.
                            threadData.ResetBinaryFileStateData(CurrentFile, dataFlags);
                        }

                        // Calling IsNewTime() can change _curTime.
                        if (IsNewTime(explicitUtcTime) || recursive)
                        {
                            // Time differs from previous line.
                            // Set the flag indicating it will be written
                            dataFlags |= DataFlags.Time;
                        }

                        // Possibly start the circular log based on _curTime and/or file size.
                        // Put this after calling IsNewTime() so _curTime will have
                        // the latest DateTime value.
                        if (FullFilePolicy == FullFilePolicy.Wrap && !recursive && !CircularStarted &&
                            (_curTime >= _circularStartTime || (CircularStartSizeKb > 0 && (_logfile.BaseStream.Position - _openSize) >= CircularStartSizeKb << 10)))
                        {
                            // This will start the circular part of the log if there is enough
                            // room based on current file position and max file size.
                            // It will increment _curBlock if it starts the circular log.
                            // It will also make a recursive call to this method via Metalog.
                            StartCircular(logger, lineLevel);
                        }

                        // Set bits in Flags that indicate what data should be written for this line.
                        dataFlags = SetDataFlags(dataFlags, threadData, fileThreadState, logger, lineLevel);

                        // We need to know the start position of the line we're about
                        // to write to determine if it overwrites the beginning of the oldest block.
                        long startPos = _logfile.BaseStream.Position;

                        // We capture the size of the file before writing the message so we can tell
                        // if the size changes.
                        long startSize = _logfile.BaseStream.Length;

                        // Write the Flags to the file followed by the data the Flags say to log.
                        WriteData(dataFlags, threadData, fileThreadState, logger, lineLevel, msg);

                        // If the file is being viewed, this will notify the viewer that the file was changed.
                        _viewerSignaler.SignalEvents();

                        if (CircularStarted)
                        {
                            ManageCircularPart(startPos, startSize, dataFlags);
                        }
                        else if (_logfile.BaseStream.Position >= _maxFilePosition)
                        {
                            // We can't do any meta-logging here because the viewer expects the first record to reach
                            // _maxFilePosition (which we just wrote) to be the last.  Writing another record would cause errors.

                            switch (FullFilePolicy)
                            {
                            case FullFilePolicy.Close:
                                Close();
                                break;

                            case FullFilePolicy.Roll:
                                // If logging a method-entry or method-exit, wait until the next call
                                // to close and open.
                                if ((dataFlags & (DataFlags.MethodEntry | DataFlags.MethodExit)) == 0)
                                {
                                    // These calls may raise events whose handlers modify our properties.
                                    Close();
                                    Open();
                                }
                                break;

                            case FullFilePolicy.Wrap:
                                // Reaching max file size/position without being in circular mode means we'll never write to
                                // this file again, so we might as well close it.  Since this is probably not what the user intended,
                                // also log an event.
                                string errmsg = "The maximum file size of " + _maxFilePosition + " was reached before circular logging was engaged.  The log file is " + FullPath;
                                Logger.EventLogging.Log(errmsg, Logger.EventLogging.MaxFileSizeReached);
                                Close();
                                break;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    // Give up!  close the log file, free whatever memory we can.
                    Logger.EventLogging.Log("An exception was thrown while logging: " + ex.ToString(), Logger.EventLogging.ExceptionInLogger);
                    Close();
                }

                return(_lineCnt);
            }
        }