Example #1
0
        private void Add(string line, LevelFlags level, int numberOfLinesRead, DateTime?timestamp)
        {
            if (_properties.GetValue(LogFileProperties.StartTimestamp) == null)
            {
                _properties.SetValue(LogFileProperties.StartTimestamp, timestamp);
            }
            if (timestamp != null)
            {
                _properties.SetValue(LogFileProperties.EndTimestamp, timestamp);
            }

            var duration = timestamp - _properties.GetValue(LogFileProperties.StartTimestamp);

            _properties.SetValue(LogFileProperties.Duration, duration);


            lock (_syncRoot)
            {
                int lineIndex  = _entries.Count;
                var logLine    = new LogLine(lineIndex, lineIndex, line, level, timestamp);
                var translated = Translate(logLine);
                _entries.Add(translated);
                _maxCharactersPerLine = Math.Max(_maxCharactersPerLine, translated.Message?.Length ?? 0);

                if (timestamp != null)
                {
                    UpdateLastModifiedIfNecessary(timestamp.Value);
                }
            }

            Listeners.OnRead(numberOfLinesRead);
        }
Example #2
0
        private bool TryAddLogEntry(List <LogLine> logEntry)
        {
            if (_indices.Count > 0 && logEntry.Count > 0 &&
                _indices[_indices.Count - 1] == logEntry[logEntry.Count - 1].LineIndex)
            {
                return(true);
            }

            if (_logEntryFilter.PassesFilter(logEntry))
            {
                lock (_indices)
                {
                    if (logEntry.Count > 0)
                    {
                        foreach (LogLine line in logEntry)
                        {
                            _indices.Add(line.LineIndex);
                            _logEntryIndices[line.LineIndex] = _currentLogEntryIndex;
                            _maxCharactersPerLine            = Math.Max(_maxCharactersPerLine, line.Message?.Length ?? 0);
                        }
                        ++_currentLogEntryIndex;
                    }
                }
                Listeners.OnRead(_indices.Count);
                return(true);
            }

            return(false);
        }
Example #3
0
        private bool TryAddLogEntry(IReadOnlyList <IReadOnlyLogEntry> logEntry)
        {
            if (_indices.Count > 0 && logEntry.Count > 0 &&
                _indices[_indices.Count - 1] == logEntry[logEntry.Count - 1].Index)
            {
                return(true);
            }

            if (_logEntryFilter.PassesFilter(logEntry))
            {
                lock (_indices)
                {
                    if (logEntry.Count > 0)
                    {
                        foreach (var line in logEntry)
                        {
                            _indices.Add((int)line.Index);
                            _logEntryIndices[(int)line.Index] = _currentLogEntryIndex;
                            _maxCharactersPerLine             = Math.Max(_maxCharactersPerLine, line.RawContent?.Length ?? 0);
                        }
                        ++_currentLogEntryIndex;
                    }
                }
                Listeners.OnRead(_indices.Count);
                return(true);
            }

            return(false);
        }
        private bool Process(IReadOnlyList <LogSourceModification> pendingModifications)
        {
            if (pendingModifications.Count == 0)
            {
                return(false);
            }

            foreach (var modification in pendingModifications)
            {
                if (modification.IsReset())
                {
                    _count = 0;
                    Listeners.Reset();
                    _propertiesBuffer.SetToDefault(_adornedProperties);
                    SynchronizeProperties();
                }
                else if (modification.IsRemoved(out var removedSection))
                {
                    _count = (int)removedSection.Index;
                    SynchronizeProperties();
                    Listeners.Remove((int)removedSection.Index, removedSection.Count);
                }
                else if (modification.IsAppended(out var appendedSection))
                {
                    Process(appendedSection);
                    _count += appendedSection.Count;
                    SynchronizeProperties();
                    Listeners.OnRead(_count);
                }
            }

            return(true);
        }
Example #5
0
        /// <summary>
        ///    Processes all newly arrived log entries.
        /// </summary>
        /// <param name="token"></param>
        private void ProcessNewLogEntries(CancellationToken token)
        {
            if (!_fullSourceSection.IsEndOfSection(_currentSourceIndex))
            {
                int remaining   = _fullSourceSection.Index + _fullSourceSection.Count - _currentSourceIndex;
                int nextCount   = Math.Min(remaining, BatchSize);
                var nextSection = new LogSourceSection(_currentSourceIndex, nextCount);
                _source.GetEntries(nextSection, _array);

                for (int i = 0; i < nextCount; ++i)
                {
                    if (token.IsCancellationRequested)
                    {
                        break;
                    }

                    var logEntry = _array[i];
                    if (Log.IsDebugEnabled)
                    {
                        Log.DebugFormat("Processing: LineIndex={0}, OriginalLineIndex={1}, LogEntryIndex={2}, Message={3}",
                                        logEntry.Index,
                                        logEntry.OriginalIndex,
                                        logEntry.LogEntryIndex,
                                        logEntry.RawContent);
                    }

                    if (_lastLogBuffer.Count == 0 || _lastLogBuffer[0].LogEntryIndex == logEntry.LogEntryIndex)
                    {
                        TryAddLogLine(logEntry);
                    }
                    else if (logEntry.LogEntryIndex != _lastLogBuffer[0].LogEntryIndex)
                    {
                        TryAddLogEntry(_lastLogBuffer);
                        _lastLogBuffer.Clear();
                        TryAddLogLine(logEntry);
                    }
                }

                _currentSourceIndex += nextCount;
            }

            // Now that we've processes all newly added log entries, we can check if we're at the end just yet...
            if (_fullSourceSection.IsEndOfSection(_currentSourceIndex))
            {
                TryAddLogEntry(_lastLogBuffer);
                UpdateProperties();                 //< we need to update our own properties after we've added the last entry, but before we notify listeners...
                Listeners.OnRead(_indices.Count);

                if (_properties.GetValue(Core.Properties.PercentageProcessed) == Percentage.HundredPercent)
                {
                    Listeners.Flush();
                }
            }
            else
            {
                UpdateProperties();
            }
        }
Example #6
0
 private void Clear()
 {
     _fullSourceSection = new LogFileSection();
     lock (_indices)
     {
         _indices.Clear();
         _logEntryIndices.Clear();
         _currentLogEntryIndex = 0;
     }
     Listeners.OnRead(-1);
 }
        /// <inheritdoc />
        protected override TimeSpan RunOnce(CancellationToken token)
        {
            bool performedWork = false;

            // Every Process() invocation locks the sync root until
            // the changes have been processed. The goal is to minimize
            // total process time and to prevent locking for too long.
            // The following number has been empirically determined
            // via testing and it felt alright :P
            const int maxLineCount = 10000;

            if (_pendingModifications.TryDequeueUpTo(maxLineCount, out var modifications))
            {
                foreach (var modification in modifications)
                {
                    if (modification.IsReset())
                    {
                        Clear();
                    }
                    else if (modification.IsRemoved(out var removedSection))
                    {
                        Remove(removedSection);
                    }
                    else if (modification.IsAppended(out var appendedSection))
                    {
                        Append(appendedSection);
                    }

                    performedWork = true;
                }
            }

            UpdateProperties();

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

            Listeners.OnRead((int)_currentSourceIndex);

            if (_properties.GetValue(Core.Properties.PercentageProcessed) == Percentage.HundredPercent)
            {
                Listeners.Flush();
            }

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

            return(_maximumWaitTime);
        }
Example #8
0
 private void Clear()
 {
     _fullSourceSection  = new LogFileSection(0, 0);
     _currentSourceIndex = 0;
     _currentLogEntry    = new LogEntryInfo(-1, 0);
     lock (_syncRoot)
     {
         _indices.Clear();
     }
     Listeners.OnRead(-1);
 }
        protected override TimeSpan RunOnce(CancellationToken token)
        {
            var pendingSections = _pendingSections.DequeueAll();

            if (!Process(pendingSections))
            {
                SynchronizeProperties();
                Listeners.OnRead(_count);
            }

            return(_maximumWaitTime);
        }
Example #10
0
        private void Add(string line, int numberOfLinesRead)
        {
            lock (_syncRoot)
            {
                _entries.Add(new LogEntry
                {
                    RawContent = line
                });
            }

            Listeners.OnRead(numberOfLinesRead);
        }
Example #11
0
        private void Add(string line, LevelFlags level, int numberOfLinesRead, DateTime?timestamp)
        {
            if (_properties.GetValue(LogFileProperties.StartTimestamp) == null)
            {
                _properties.SetValue(LogFileProperties.StartTimestamp, timestamp);
            }
            if (timestamp != null)
            {
                _properties.SetValue(LogFileProperties.EndTimestamp, timestamp);
            }

            lock (_syncRoot)
            {
                int lineIndex  = _entries.Count;
                var logLine    = new LogLine(lineIndex, lineIndex, line, level, timestamp);
                var translated = Translate(logLine);
                _entries.Add(translated);
                _maxCharactersPerLine = Math.Max(_maxCharactersPerLine, translated.Message?.Length ?? 0);

                if (timestamp != null)
                {
                    var lastModified = _properties.GetValue(LogFileProperties.LastModified);
                    var difference   = timestamp - lastModified;
                    if (difference >= TimeSpan.FromSeconds(10))
                    {
                        // I've had this issue occur on one system and I can't really explain it.
                        // For some reason, new FileInfo(...).LastWriteTime will not give correct
                        // results when we can see that the bloody file is being written to as we speak.
                        // As a work around, we'll just use the timestamp of the log file as lastModifed
                        // if that happens to be newer.
                        //
                        // This might be related to files being consumed from a network share. Anyways,
                        // this quick fix should improve user feedback...
                        if (!_loggedTimestampWarning)
                        {
                            Log.InfoFormat(
                                "FileInfo.LastWriteTime results in a time stamp that is less than the parsed timestamp (LastWriteTime={0}, Parsed={1}), using parsed instead",
                                lastModified,
                                timestamp
                                );
                            _loggedTimestampWarning = true;
                        }

                        _properties.SetValue(LogFileProperties.LastModified, timestamp.Value);
                    }
                }
            }

            Listeners.OnRead(numberOfLinesRead);
        }
Example #12
0
        private void AppendSection(LogSourceSection section)
        {
            _count = (int)(section.Index + section.Count);
            try
            {
                _source.GetEntries(section, _fetchBuffer);
                OnSectionAppended(section, _fetchBuffer, _count);
            }
            catch (Exception e)
            {
                Log.WarnFormat("Caught unexpected exception: {0}", e);
            }

            SynchronizeProperties();
            Listeners.OnRead(_count);
        }
Example #13
0
        /// <inheritdoc />
        protected override TimeSpan RunOnce(CancellationToken token)
        {
            bool performedWork = false;

            while (_pendingModifications.TryDequeue(out var nextSection) && !token.IsCancellationRequested)
            {
                if (nextSection.IsReset)
                {
                    Clear();
                }
                else if (nextSection.IsInvalidate)
                {
                    Invalidate(nextSection);
                }
                else
                {
                    Append(nextSection);
                }

                performedWork = true;
            }

            // 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);
        }
Example #14
0
 private void NotifyListeners(IEnumerable <LogFileSection> changes)
 {
     foreach (var section in changes)
     {
         if (section.IsInvalidate)
         {
             Listeners.Invalidate((int)section.Index, section.Count);
         }
         else if (section.IsReset)
         {
             Listeners.Reset();
         }
         else
         {
             Listeners.OnRead((int)(section.Index + section.Count));
         }
     }
 }
Example #15
0
 private void NotifyListeners(IEnumerable <LogSourceModification> changes)
 {
     foreach (var section in changes)
     {
         if (section.IsRemoved(out var removedSection))
         {
             Listeners.Remove((int)removedSection.Index, removedSection.Count);
         }
         else if (section.IsReset())
         {
             Listeners.Reset();
         }
         else if (section.IsAppended(out var appendedSection))
         {
             Listeners.OnRead((int)(appendedSection.Index + appendedSection.Count));
         }
     }
 }
Example #16
0
        private void ProcessPendingSections(out bool workDone)
        {
            workDone = false;
            while (_pendingSections.TryDequeue(out var pair))
            {
                // We may still have pending sections from a log file we've just removed as listener.
                // If that's the case, then throw away that section and go look for the next...
                if (!Equals(pair.Key, _finalLogSource))
                {
                    continue;
                }

                var modification = pair.Value;
                if (modification.IsReset())
                {
                    Listeners.Reset();
                    _count = 0;
                    _maxCharactersInLine = 0;
                }
                else if (modification.IsRemoved(out var removedSection))
                {
                    Listeners.Remove((int)removedSection.Index, removedSection.Count);
                    _count = (int)removedSection.Index;
                    // TODO: What about max width?
                }
                else if (modification.IsAppended(out var appendedSection))
                {
                    Listeners.OnRead(appendedSection.LastIndex);
                    _count = (int)(appendedSection.Index + appendedSection.Count);
                    UpdateMaxWidth(appendedSection, pair.Key);
                }

                workDone = true;
            }

            if (!workDone)
            {
                Listeners.OnRead(_count);
            }
        }
Example #17
0
        private void Clear(ILogFile logFile)
        {
            var numRemoved = 0;

            lock (_syncRoot)
            {
                for (var i = _indices.Count - 1; i >= 0; --i)
                {
                    var index        = _indices[i];
                    var indexLogFile = _sources[index.LogFileIndex];
                    if (indexLogFile == logFile)
                    {
                        _indices.RemoveAt(i);
                        ++numRemoved;
                    }
                }
            }

            if (numRemoved > 0)
            {
                Listeners.Reset();
                Listeners.OnRead(_indices.Count);
            }
        }
Example #18
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);
        }
Example #19
0
        /// <inheritdoc />
        protected override TimeSpan RunOnce(CancellationToken token)
        {
            bool read = false;

            try
            {
                if (!File.Exists(_fileName))
                {
                    SetDoesNotExist();
                }
                else
                {
                    var info     = new FileInfo(_fileName);
                    var fileSize = info.Length;
                    _localProperties.SetValue(Core.Properties.LastModified, info.LastWriteTimeUtc);
                    _localProperties.SetValue(Core.Properties.Created, info.CreationTimeUtc);
                    _localProperties.SetValue(Core.Properties.Size, Size.FromBytes(fileSize));
                    UpdatePercentageProcessed(_lastStreamPosition, fileSize, allow100Percent: true);
                    SynchronizePropertiesWithUser();

                    using (var stream = new FileStream(_fileName,
                                                       FileMode.Open,
                                                       FileAccess.Read,
                                                       FileShare.ReadWrite))
                    {
                        using (var reader = new StreamReaderEx(stream, _encoding))
                        {
                            // We change the error flag explicitly AFTER opening
                            // the stream because that operation might throw if we're
                            // not allowed to access the file (in which case a different
                            // error must be set).

                            _localProperties.SetValue(Core.Properties.EmptyReason, null);
                            if (stream.Length >= _lastStreamPosition)
                            {
                                stream.Position = _lastStreamPosition;
                            }
                            else
                            {
                                OnReset(stream, out _numberOfLinesRead, out _lastStreamPosition);
                            }

                            int    numProcessed = 0;
                            string currentLine;
                            while ((currentLine = reader.ReadLine()) != null)
                            {
                                token.ThrowIfCancellationRequested();

                                bool lastLineHadNewline = _lastLineHadNewline;
                                var  trimmedLine        = currentLine.TrimNewlineEnd(out _lastLineHadNewline);
                                var  entryCount         = _entries.Count;
                                if (entryCount > 0 && !lastLineHadNewline)
                                {
                                    // We need to remove the last line and create a new line
                                    // that consists of the entire content.
                                    RemoveLast();
                                    trimmedLine        = _untrimmedLastLine + trimmedLine;
                                    _untrimmedLastLine = _untrimmedLastLine + currentLine;
                                }
                                else
                                {
                                    _untrimmedLastLine = currentLine;
                                    ++_numberOfLinesRead;
                                    read = true;
                                }

                                Add(trimmedLine,
                                    _numberOfLinesRead);

                                if (++numProcessed % 1000 == 0)
                                {
                                    // Here's the deal: Since we're processing the file in chunks, we advance the underlying
                                    // stream faster than we're actually consuming lines. This means that it's quite likely
                                    // that at the end of the file, we have moved the stream to the end, but have not quite
                                    // yet processed the underlying buffer from StreamReaderEx. The percentage processed
                                    // should be accurate enough so that if it is at 100%, then no more log entries are added.
                                    // We can only guarantee that when we have processed all lines and therefore we reserve
                                    // setting the percentage to 100% ONLY when we can read no more lines
                                    // (See the SetEndOfSourceReached() call below, outside the loop).
                                    UpdatePercentageProcessed(stream.Position, fileSize, allow100Percent: false);

                                    SynchronizePropertiesWithUser();
                                }
                            }

                            _lastStreamPosition = stream.Position;
                            _localProperties.SetValue(TextProperties.LineCount, _entries.Count);
                            _localProperties.SetValue(Core.Properties.LogEntryCount, _entries.Count);
                        }
                    }

                    Listeners.OnRead(_numberOfLinesRead);
                    SetEndOfSourceReached();
                }
            }
            catch (FileNotFoundException e)
            {
                SetError(_sourceDoesNotExist);
                Log.Debug(e);
            }
            catch (DirectoryNotFoundException e)
            {
                SetError(_sourceDoesNotExist);
                Log.Debug(e);
            }
            catch (OperationCanceledException e)
            {
                Log.Debug(e);
            }
            catch (UnauthorizedAccessException e)
            {
                SetError(_sourceCannotBeAccessed);
                Log.Debug(e);
            }
            catch (IOException e)
            {
                SetError(_sourceCannotBeAccessed);
                Log.Debug(e);
            }
            catch (Exception e)
            {
                Log.Debug(e);
            }

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

            return(TimeSpan.FromMilliseconds(100));
        }
Example #20
0
        protected override TimeSpan RunOnce(CancellationToken token)
        {
            try
            {
                var info = new FileInfo(_fileName);
                _fileSize = Size.FromBytes(info.Length);

                if (info.Exists)
                {
                    var builder = new SQLiteConnectionStringBuilder
                    {
                        DataSource = _fileName,
                        Version    = 3
                    };
                    using (var connection = new SQLiteConnection(builder.ToString()))
                    {
                        connection.Open();
                        int lineCount = GetNumberOfLogEntries(connection);
                        if (lineCount < _lineCount)
                        {
                            // We'll assume that the table was cleared...
                            Listeners.Flush();
                            _lineCount = 0;
                            lock (_syncRoot)
                            {
                                _lines.Clear();
                            }

                            var lines = ReadLogLines(connection, 0, lineCount);
                            lock (_syncRoot)
                            {
                                _lines.AddRange(lines);
                                _lineCount = lineCount;
                            }

                            Listeners.OnRead(_lineCount);
                        }
                        else if (lineCount > _lineCount)
                        {
                            var remaining = lineCount - _lineCount;
                            var lines     = ReadLogLines(connection, _lineCount, remaining);
                            lock (_syncRoot)
                            {
                                _lines.AddRange(lines);
                                _lineCount = lineCount;
                            }

                            Listeners.OnRead(_lineCount);
                        }
                        else
                        {
                            // We'll just assume that nothing relevant has been modified.
                        }
                    }

                    _exists = true;
                }
                else
                {
                    Clear();
                    _exists = false;
                }
            }
            catch (IOException e)
            {
                Log.DebugFormat("Caught exception while trying to open the database: {0}", e);

                // It's unlikely, but possible that the file happened to be deleted in between File.Exists
                // and actually opening the connection. But we should actually behave as if we've taken the else
                // branch above...
                _exists = false;
            }
            catch (Exception e)
            {
                // It's considered bad form to let exception bubble through to the task scheduler, and therefore
                // we 'll log the exception (which hopefully doesn't happen every time) ourselves...
                Log.ErrorFormat("Caught unexpected exception: {0}", e);
            }
            return(TimeSpan.FromMilliseconds(500));
        }
Example #21
0
        /// <inheritdoc />
        protected override TimeSpan RunOnce(CancellationToken token)
        {
            PendingModification modification;

            while (_pendingModifications.TryDequeue(out modification))
            {
                if (token.IsCancellationRequested)
                {
                    return(TimeSpan.Zero);
                }

                _totalLineCount = CalculateTotalLogLineCount();
                _progress       = Percentage.Of(_indices.Count, _totalLineCount);

                if (modification.Section.IsReset)
                {
                    Clear(modification.LogFile);
                }
                else if (modification.Section.IsInvalidate)
                {
                    throw new NotImplementedException();
                }
                else
                {
                    for (var i = 0; i < modification.Section.Count; ++i)
                    {
                        var sourceIndex = modification.Section.Index + i;
                        var newLogLine  = modification.LogFile.GetLine((int)sourceIndex);
                        if (newLogLine.Timestamp != null)
                        {
                            // We need to find out where this new entry (or entries) is/are to be inserted.
                            var  insertionIndex = _indices.Count;
                            byte logFileIndex;
                            _logFileIndices.TryGetValue(modification.LogFile, out logFileIndex);
                            for (var n = _indices.Count - 1; n >= 0; --n)
                            {
                                var idx     = _indices[n];
                                var logFile = _sources[idx.LogFileIndex];
                                var entry   = logFile.GetLine(idx.SourceLineIndex);
                                if (entry.Timestamp <= newLogLine.Timestamp)
                                {
                                    insertionIndex = n + 1;
                                    break;
                                }
                                if (entry.Timestamp > newLogLine.Timestamp)
                                {
                                    insertionIndex = n;
                                }
                            }

                            var mergedLogEntryIndex = GetMergedLogEntryIndex(modification.LogFile, insertionIndex, newLogLine);
                            var index = new Index((int)sourceIndex,
                                                  mergedLogEntryIndex,
                                                  newLogLine.LogEntryIndex,
                                                  logFileIndex);
                            if (insertionIndex < _indices.Count)
                            {
                                InvalidateOnward(insertionIndex, modification.LogFile, newLogLine);
                            }

                            lock (_syncRoot)
                            {
                                _indices.Insert(insertionIndex, index);
                                _maxCharactersPerLine = Math.Max(_maxCharactersPerLine, newLogLine.Message?.Length ?? 0);
                            }

                            Listeners.OnRead(_indices.Count);

                            // There's no need to frantically update every time, but every
                            // once in a while would be nice...
                            if (i % 100 == 0)
                            {
                                UpdateProperties();
                            }
                        }
                    }
                }
            }

            UpdateProperties();

            Listeners.OnRead(_indices.Count);
            SetEndOfSourceReached();

            return(_maximumWaitTime);
        }
Example #22
0
        /// <inheritdoc />
        protected override TimeSpan RunOnce(CancellationToken token)
        {
            bool performedWork = false;

            LogFileSection section;

            while (_pendingModifications.TryDequeue(out section) && !token.IsCancellationRequested)
            {
                if (section.IsReset)
                {
                    Clear();
                    _lastLogEntry.Clear();
                    _currentSourceIndex = 0;
                }
                else if (section.IsInvalidate)
                {
                    LogLineIndex startIndex = section.Index;
                    _fullSourceSection = new LogFileSection(0, (int)startIndex);

                    if (_currentSourceIndex > _fullSourceSection.LastIndex)
                    {
                        _currentSourceIndex = (int)section.Index;
                    }

                    Invalidate(_currentSourceIndex);
                    RemoveInvalidatedLines(_lastLogEntry, _currentSourceIndex);
                }
                else
                {
                    _fullSourceSection = LogFileSection.MinimumBoundingLine(_fullSourceSection, section);
                }

                performedWork = true;
            }

            if (!_fullSourceSection.IsEndOfSection(_currentSourceIndex))
            {
                int remaining   = _fullSourceSection.Index + _fullSourceSection.Count - _currentSourceIndex;
                int nextCount   = Math.Min(remaining, BatchSize);
                var nextSection = new LogFileSection(_currentSourceIndex, nextCount);
                _source.GetSection(nextSection, _buffer);

                for (int i = 0; i < nextCount; ++i)
                {
                    if (token.IsCancellationRequested)
                    {
                        break;
                    }

                    LogLine line = _buffer[i];
                    if (_lastLogEntry.Count == 0 || _lastLogEntry[0].LogEntryIndex == line.LogEntryIndex)
                    {
                        TryAddLogLine(line);
                    }
                    else if (line.LogEntryIndex != _lastLogEntry[0].LogEntryIndex)
                    {
                        TryAddLogEntry(_lastLogEntry);
                        _lastLogEntry.Clear();
                        TryAddLogLine(line);
                    }
                }

                _currentSourceIndex += nextCount;
            }

            if (_fullSourceSection.IsEndOfSection(_currentSourceIndex))
            {
                TryAddLogEntry(_lastLogEntry);
                Listeners.OnRead(_indices.Count);

                if (_source.EndOfSourceReached)
                {
                    SetEndOfSourceReached();
                }
            }

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

            return(_maximumWaitTime);
        }
Example #23
0
        /// <inheritdoc />
        protected override TimeSpan RunOnce(CancellationToken token)
        {
            bool read = false;

            try
            {
                if (!File.Exists(_fileName))
                {
                    SetDoesNotExist();
                }
                else
                {
                    var info = new FileInfo(_fileName);
                    _properties.SetValue(LogFileProperties.LastModified, info.LastWriteTime);
                    _properties.SetValue(LogFileProperties.Created, info.CreationTime);
                    _properties.SetValue(LogFileProperties.Size, Size.FromBytes(info.Length));

                    using (var stream = new FileStream(_fileName,
                                                       FileMode.Open,
                                                       FileAccess.Read,
                                                       FileShare.ReadWrite))
                    {
                        var format = _properties.GetValue(LogFileProperties.Format);
                        if (format == null)
                        {
                            format = TryFindFormat(stream);
                            _properties.SetValue(LogFileProperties.Format, format);
                        }

                        var encoding = format?.Encoding ?? _encoding;
                        _properties.SetValue(LogFileProperties.Encoding, encoding);
                        using (var reader = new StreamReaderEx(stream, encoding))
                        {
                            // We change the error flag explicitly AFTER opening
                            // the stream because that operation might throw if we're
                            // not allowed to access the file (in which case a different
                            // error must be set).

                            _properties.SetValue(LogFileProperties.EmptyReason, ErrorFlags.None);
                            if (stream.Length >= _lastPosition)
                            {
                                stream.Position = _lastPosition;
                            }
                            else
                            {
                                OnReset(stream, out _numberOfLinesRead, out _lastPosition);
                            }

                            string currentLine;
                            while ((currentLine = reader.ReadLine()) != null)
                            {
                                token.ThrowIfCancellationRequested();

                                ResetEndOfSourceReached();

                                LevelFlags level = LogLine.DetermineLevelFromLine(currentLine);

                                bool lastLineHadNewline = _lastLineHadNewline;
                                var  trimmedLine        = currentLine.TrimNewlineEnd(out _lastLineHadNewline);
                                var  entryCount         = _entries.Count;
                                if (entryCount > 0 && !lastLineHadNewline)
                                {
                                    // We need to remove the last line and create a new line
                                    // that consists of the entire content.
                                    RemoveLast();
                                    trimmedLine        = _untrimmedLastLine + trimmedLine;
                                    _untrimmedLastLine = _untrimmedLastLine + currentLine;
                                }
                                else
                                {
                                    _untrimmedLastLine = currentLine;
                                    ++_numberOfLinesRead;
                                    read = true;
                                }

                                var timestamp = ParseTimestamp(trimmedLine);
                                Add(trimmedLine, level, _numberOfLinesRead, timestamp);
                            }

                            _lastPosition = stream.Position;
                        }
                    }

                    Listeners.OnRead(_numberOfLinesRead);
                    SetEndOfSourceReached();
                }
            }
            catch (FileNotFoundException e)
            {
                SetError(ErrorFlags.SourceDoesNotExist);
                Log.Debug(e);
            }
            catch (DirectoryNotFoundException e)
            {
                SetError(ErrorFlags.SourceDoesNotExist);
                Log.Debug(e);
            }
            catch (OperationCanceledException e)
            {
                Log.Debug(e);
            }
            catch (UnauthorizedAccessException e)
            {
                SetError(ErrorFlags.SourceCannotBeAccessed);
                Log.Debug(e);
            }
            catch (IOException e)
            {
                SetError(ErrorFlags.SourceCannotBeAccessed);
                Log.Debug(e);
            }
            catch (Exception e)
            {
                Log.Debug(e);
            }

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

            return(TimeSpan.FromMilliseconds(100));
        }