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); } } } }
private void Clear() { _fullSourceSection = new LogFileSection(0, 0); _currentSourceIndex = 0; _currentLogEntry = new LogEntryInfo(-1, 0); lock (_syncRoot) { _indices.Clear(); } Listeners.OnRead(-1); }
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); } }
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); }
/// <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(); }
/// <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); }