Beispiel #1
0
        private void Append(LogFileSection section)
        {
            var buffer = new LogLine[section.Count];

            _source.GetSection(section, buffer);

            lock (_syncRoot)
            {
                for (var i = 0; i < section.Count; ++i)
                {
                    var line = buffer[i];

                    if (_currentLogEntry.EntryIndex.IsInvalid ||
                        !AppendToCurrentLogEntry(line))
                    {
                        _currentLogEntry          = _currentLogEntry.NextEntry(line.LineIndex);
                        _currentLogEntryLevel     = line.Level;
                        _currentLogEntryTimestamp = line.Timestamp;
                    }

                    _indices.Add(_currentLogEntry);
                }
            }

            _currentSourceIndex += section.Count;
            _fullSourceSection   = new LogFileSection(0, _currentSourceIndex.Value);
        }
        /// <summary>
        ///     Initializes this object.
        /// </summary>
        /// <remarks>
        ///    Plugin authors are deliberately prevented from calling this constructor directly because it's signature may change
        ///    over time. In order to create an instance of this type, simply call <see cref="ILogSourceFactory.CreateMultiLineLogFile"/>.
        /// </remarks>
        /// <param name="taskScheduler"></param>
        /// <param name="source"></param>
        /// <param name="maximumWaitTime"></param>
        public MultiLineLogSource(ITaskScheduler taskScheduler, ILogSource source, TimeSpan maximumWaitTime)
            : base(taskScheduler)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            _maximumWaitTime      = maximumWaitTime;
            _pendingModifications = new ConcurrentQueue <LogSourceModification>();
            _syncRoot             = new object();
            _specialColumns       = new HashSet <IColumnDescriptor> {
                Core.Columns.LogEntryIndex, Core.Columns.Timestamp, Core.Columns.LogLevel
            };
            _indices = new List <LogEntryInfo>();

            // The log file we were given might offer even more properties than the minimum set and we
            // want to expose those as well.
            _propertiesBuffer = new PropertiesBufferList(Core.Properties.CombineWithMinimum(source.Properties));
            _propertiesBuffer.SetValue(Core.Properties.EmptyReason, null);

            _properties = new ConcurrentPropertiesList(Core.Properties.CombineWithMinimum(source.Properties));
            _properties.CopyFrom(_propertiesBuffer);

            _currentLogEntry = new LogEntryInfo(-1, 0);

            _source = source;
            _source.AddListener(this, maximumWaitTime, MaximumBatchSize);
            StartTask();
        }
        private void Append(LogSourceSection section)
        {
            var buffer = new LogBufferArray(section.Count, Core.Columns.Index, Core.Columns.Timestamp, Core.Columns.LogLevel);

            _source.GetEntries(section, buffer);

            lock (_syncRoot)
            {
                for (var i = 0; i < section.Count; ++i)
                {
                    var line = buffer[i];

                    if (_currentLogEntry.EntryIndex.IsInvalid ||
                        !AppendToCurrentLogEntry(line))
                    {
                        _currentLogEntry = _currentLogEntry.NextEntry(line.Index);
                    }

                    _indices.Add(_currentLogEntry);
                }
            }

            _currentSourceIndex += section.Count;
            _fullSourceSection   = new LogSourceSection(0, _currentSourceIndex.Value);
        }
        /// <summary>
        /// Parses Log Entries from the collection of log nodes.
        /// </summary>
        /// <param name="nodes">The collection of Xml nodes which are valid LogEntry nodes.</param>
        /// <param name="result">The TestResult which will host the parsed LogEntries.</param>
        private static void ParseTestCaseLogEntries(XmlNodeList nodes, TestResult result)
        {
            foreach (XmlNode child in nodes)
            {
                if (child.NodeType == XmlNodeType.Element)
                {
                    LogEntry entry = null;

                    switch (child.Name)
                    {
                    case Xml.Info: entry = new LogEntryInfo(child.InnerText); break;

                    case Xml.Message: entry = new LogEntryMessage(child.InnerText); break;

                    case Xml.Warning: entry = new LogEntryWarning(child.InnerText); break;

                    case Xml.Error: entry = ParseTestCaseLogError(child); break;

                    case Xml.FatalError: entry = new LogEntryFatalError(child.InnerText); break;

                    case Xml.Exception: entry = ParseTestCaseLogException(child); break;
                    }

                    if (entry != null)
                    {
                        entry.Source = ParseSourceInfo(child);
                        result.LogEntries.Add(entry);
                    }
                }
            }
        }
Beispiel #5
0
 private void Clear()
 {
     _fullSourceSection  = new LogFileSection(0, 0);
     _currentSourceIndex = 0;
     _currentLogEntry    = new LogEntryInfo(-1, 0);
     lock (_syncRoot)
     {
         _indices.Clear();
     }
     Listeners.OnRead(-1);
 }
Beispiel #6
0
        private void Invalidate(LogFileSection sectionToInvalidate)
        {
            var firstInvalidIndex   = LogLineIndex.Min(_fullSourceSection.LastIndex, sectionToInvalidate.Index);
            var lastInvalidIndex    = LogLineIndex.Min(_fullSourceSection.LastIndex, sectionToInvalidate.LastIndex);
            var invalidateCount     = lastInvalidIndex - firstInvalidIndex + 1;
            var previousSourceIndex = _currentSourceIndex;

            _fullSourceSection = new LogFileSection(0, (int)firstInvalidIndex);
            if (_fullSourceSection.Count > 0)
            {
                // It's possible (likely) that we've received an invalidation for a region of the source
                // that we've already processed (i.e. created indices for). If that's the case, then we need
                // to rewind the index. Otherwise nothing needs to be done...
                var newIndex = _fullSourceSection.LastIndex + 1;
                if (newIndex < _currentSourceIndex)
                {
                    _currentSourceIndex = newIndex;
                }
            }
            else
            {
                _currentSourceIndex = 0;
            }

            lock (_syncRoot)
            {
                var toRemove = _indices.Count - lastInvalidIndex;
                if (toRemove > 0)
                {
                    _indices.RemoveRange((int)firstInvalidIndex, toRemove);
                    _currentLogEntry = new LogEntryInfo(firstInvalidIndex - 1, 0);
                }
                if (previousSourceIndex != _currentSourceIndex)
                {
                    _indices.RemoveRange((int)_currentSourceIndex, _indices.Count - _currentSourceIndex);
                }
            }

            if (_indices.Count != _currentSourceIndex)
            {
                Log.ErrorFormat("Inconsistency detected: We have {0} indices for {1} lines", _indices.Count,
                                _currentSourceIndex);
            }

            Listeners.Invalidate((int)firstInvalidIndex, invalidateCount);

            if (_fullSourceSection.Count > firstInvalidIndex)
            {
                _fullSourceSection = new LogFileSection(0, firstInvalidIndex.Value);
            }
        }
Beispiel #7
0
        public void LogEvent(String category, Int32 eventId, params Object[] parameters)
        {
            LogEntryInfo   entry    = GetLogEntry(category, eventId);
            String         message  = "No Message";
            TraceEventType severity = TraceEventType.Information;

            if (entry != null)
            {
                message  = entry.Message;
                severity = entry.Severity;
            }
            if (parameters != null && parameters.Length > 0)
            {
                message = String.Format(message, parameters);
            }
            LogEvent(category, eventId, message, severity);
        }
Beispiel #8
0
        /// <summary>
        ///     Initializes this object.
        /// </summary>
        /// <remarks>
        ///    Plugin authors are deliberately prevented from calling this constructor directly because it's signature may change
        ///    over time. In order to create an instance of this type, simply call <see cref="IServiceContainer.CreateMultiLineLogFile"/>.
        /// </remarks>
        /// <param name="taskScheduler"></param>
        /// <param name="source"></param>
        /// <param name="maximumWaitTime"></param>
        public MultiLineLogFile(ITaskScheduler taskScheduler, ILogFile source, TimeSpan maximumWaitTime)
            : base(taskScheduler)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            _maximumWaitTime      = maximumWaitTime;
            _pendingModifications = new ConcurrentQueue <LogFileSection>();
            _syncRoot             = new object();
            _indices = new List <LogEntryInfo>();

            // The log file we were given might offer even more properties than the minimum set and we
            // want to expose those as well.
            _properties = new LogFilePropertyList(LogFileProperties.CombineWithMinimum(source.Properties));
            _properties.SetValue(LogFileProperties.EmptyReason, ErrorFlags.SourceDoesNotExist);

            _currentLogEntry = new LogEntryInfo(-1, 0);

            _source = source;
            _source.AddListener(this, maximumWaitTime, MaximumBatchSize);
            StartTask();
        }
Beispiel #9
0
        /// <inheritdoc />
        protected override TimeSpan RunOnce(CancellationToken token)
        {
            var  lastCount     = _fullSourceSection.Count;
            bool performedWork = false;

            LogFileSection section;

            while (_pendingModifications.TryDequeue(out section) && !token.IsCancellationRequested)
            {
                if (section.IsReset)
                {
                    Clear();
                }
                else if (section.IsInvalidate)
                {
                    Invalidate(section);
                }
                else
                {
                    _fullSourceSection = LogFileSection.MinimumBoundingLine(_fullSourceSection, section);
                }
                performedWork = true;
            }

            if (!_fullSourceSection.IsEndOfSection(_currentSourceIndex))
            {
                var remaining = Math.Min(_fullSourceSection.Count - _currentSourceIndex, MaximumBatchSize);
                var buffer    = new LogLine[remaining];
                _source.GetSection(new LogFileSection(_currentSourceIndex, remaining), buffer);
                LogLineIndex?resetIndex = null;

                lock (_syncRoot)
                {
                    for (var i = 0; i < remaining; ++i)
                    {
                        var line = buffer[i];
                        if (_currentLogEntry.EntryIndex.IsInvalid ||
                            line.Level != LevelFlags.None ||
                            _currentLogEntryLevel == LevelFlags.None)
                        {
                            _currentLogEntry      = _currentLogEntry.NextEntry(line.LineIndex);
                            _currentLogEntryLevel = line.Level;
                        }
                        else if (_currentLogEntry.FirstLineIndex < lastCount && resetIndex == null)
                        {
                            var index = _currentLogEntry.FirstLineIndex;
                            resetIndex = index;

                            _currentLogEntryLevel = _source.GetLine((int)index).Level;
                        }
                        _indices.Add(_currentLogEntry);
                    }
                }

                if (resetIndex != null)
                {
                    var resetCount = lastCount - resetIndex.Value;
                    if (resetCount > 0)
                    {
                        Listeners.Invalidate((int)resetIndex.Value, resetCount);
                    }
                }

                _currentSourceIndex += remaining;
            }

            // Now we can perform a block-copy of all properties.
            _source.GetValues(_properties);

            _maxCharactersPerLine = _source.MaxCharactersPerLine;

            if (_indices.Count != _currentSourceIndex)
            {
                Log.ErrorFormat("Inconsistency detected: We have {0} indices for {1} lines", _indices.Count,
                                _currentSourceIndex);
            }

            Listeners.OnRead((int)_currentSourceIndex);

            if (_source.EndOfSourceReached && _fullSourceSection.IsEndOfSection(_currentSourceIndex))
            {
                SetEndOfSourceReached();
            }

            if (performedWork)
            {
                return(TimeSpan.Zero);
            }

            return(_maximumWaitTime);
        }