diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 8aea65c8..6533ea23 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -17,7 +17,7 @@ - Serilog.Formatting.Compact format support ### Technology Stack -- **Primary Language**: C# (.NET 8.0-windows target framework) +- **Primary Language**: C# (.NET 10.0-windows target framework) - **UI Framework**: Windows Forms - **Build System**: Nuke Build System with MSBuild - **Target Platform**: Windows (requires Windows-specific dependencies) @@ -39,9 +39,9 @@ **CRITICAL**: This project requires Windows development environment and .NET 9.0.301 SDK or compatible. ### Environment Setup -1. **Install .NET SDK**: Project requires .NET 9.0.301 SDK (specified in `global.json`) -2. **Windows Environment**: Build targets `net8.0-windows` and uses Windows Forms -3. **Visual Studio**: Recommended Visual Studio 2017+ or Visual Studio Code with C# extension +1. **Install .NET SDK**: Project requires .NET 10.0.100 SDK (specified in `global.json`) +2. **Windows Environment**: Build targets `net10.0-windows` and uses Windows Forms +3. **Visual Studio**: Recommended Visual Studio 2026+ or Visual Studio Code with C# extension 4. **Optional Dependencies**: - Chocolatey (for packaging) - Inno Setup 5 or 6 (for setup creation) @@ -88,7 +88,7 @@ dotnet test --no-build --verbosity normal - **Workaround**: Use Windows environment or Windows Subsystem for Linux with proper .NET Windows SDK 2. **.NET Version Mismatch**: - - Project requires .NET 9.0.301 but may encounter .NET 8.0 environments + - Project requires .NET 10.0.100 but may encounter .NET 8.0 environments - **Workaround**: Nuke build system automatically downloads correct SDK version 3. **Build Timing**: @@ -176,7 +176,7 @@ LogExpert/ 2. **`.github/workflows/test_dotnet.yml`**: - Runs on push to Development branch - Executes unit tests - - Uses .NET 9.0.x SDK + - Uses .NET 10.0.x SDK #### AppVeyor Integration - **`appveyor.yml`**: Legacy CI configuration @@ -224,7 +224,7 @@ Key external dependencies (managed via Directory.Packages.props): #### Adding Dependencies 1. Update `src/Directory.Packages.props` for version management 2. Add `` in specific project files -3. Ensure compatibility with .NET 8.0 target framework +3. Ensure compatibility with .NET 10.0 target framework ### Build Troubleshooting - **Missing Windows SDK**: Ensure Windows development environment diff --git a/src/ColumnizerLib.UnitTests/ColumnTests.cs b/src/ColumnizerLib.UnitTests/ColumnTests.cs index 98830505..4569bf3f 100644 --- a/src/ColumnizerLib.UnitTests/ColumnTests.cs +++ b/src/ColumnizerLib.UnitTests/ColumnTests.cs @@ -10,31 +10,74 @@ namespace ColumnizerLib.UnitTests; [TestFixture] public class ColumnTests { + [SetUp] + public void SetUp() + { + // Reset to default before each test + Column.SetMaxDisplayLength(20_000); + } + + [Test] + public void Column_DisplayMaxLength_DefaultIs20000() + { + Assert.That(Column.GetMaxDisplayLength(), Is.EqualTo(20_000)); + } + [Test] - public void Column_LineCutOff () + public void Column_DisplayMaxLength_CanBeConfigured() { - var expectedFullValue = new StringBuilder().Append('6', 4675).Append("1234").ToString(); - var expectedDisplayValue = expectedFullValue[..4675] + "..."; // Using substring shorthand + Column.SetMaxDisplayLength(50_000); + Assert.That(Column.GetMaxDisplayLength(), Is.EqualTo(50_000)); + + // Reset for other tests + Column.SetMaxDisplayLength(20_000); + } + [Test] + public void Column_DisplayMaxLength_EnforcesMinimum() + { + Assert.Throws(() => Column.SetMaxDisplayLength(500)); + } + + [Test] + public void Column_TruncatesAtConfiguredDisplayLength() + { + Column.SetMaxDisplayLength(10_000); + + // Create a line longer than the display max length + var longValue = new StringBuilder().Append('X', 15_000).ToString(); + Column column = new() { - FullValue = expectedFullValue + FullValue = longValue }; - Assert.That(column.DisplayValue, Is.EqualTo(expectedDisplayValue)); - Assert.That(column.FullValue, Is.EqualTo(expectedFullValue)); + // FullValue should contain the full line + Assert.That(column.FullValue, Is.EqualTo(longValue)); + Assert.That(column.FullValue.Length, Is.EqualTo(15_000)); + + // DisplayValue should be truncated at 10,000 with "..." appended + Assert.That(column.DisplayValue.Length, Is.EqualTo(10_003)); // 10000 + "..." + Assert.That(column.DisplayValue.EndsWith("..."), Is.True); + Assert.That(column.DisplayValue.StartsWith("XXX"), Is.True); + + // Reset for other tests + Column.SetMaxDisplayLength(20_000); } [Test] - public void Column_NoLineCutOff () + public void Column_NoTruncationWhenBelowLimit() { - var expected = new StringBuilder().Append('6', 4675).ToString(); + Column.SetMaxDisplayLength(20_000); + + var normalValue = new StringBuilder().Append('Y', 5_000).ToString(); Column column = new() { - FullValue = expected + FullValue = normalValue }; Assert.That(column.DisplayValue, Is.EqualTo(column.FullValue)); + Assert.That(column.DisplayValue.Length, Is.EqualTo(5_000)); } [Test] diff --git a/src/ColumnizerLib/Column.cs b/src/ColumnizerLib/Column.cs index 4283e2df..8518ddcc 100644 --- a/src/ColumnizerLib/Column.cs +++ b/src/ColumnizerLib/Column.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; - using LogExpert; namespace ColumnizerLib; @@ -9,21 +6,22 @@ public class Column : IColumn { #region Fields - private const int MAXLENGTH = 4678 - 3; private const string REPLACEMENT = "..."; + // Display-level maximum line length (separate from reader-level limit) + // Can be configured via SetMaxDisplayLength() + private static int _maxDisplayLength = 20_000; + private static readonly List> _replacements = [ //replace tab with 3 spaces, from old coding. Needed??? input => input.Replace("\t", " ", StringComparison.Ordinal), //shorten string if it exceeds maxLength - input => input.Length > MAXLENGTH - ? string.Concat(input.AsSpan(0, MAXLENGTH), REPLACEMENT) + input => input.Length > _maxDisplayLength + ? string.Concat(input.AsSpan(0, _maxDisplayLength), REPLACEMENT) : input ]; - private string _fullValue; - #endregion #region cTor @@ -40,6 +38,9 @@ static Column () { //Everything below Win8 the installed fonts seems to not to support reliabel //Replace null char with space + //.net 10 does no longer support windows lower then windows 10 + //TODO: remove if with one of the next releases + //https://github.com/dotnet/core/blob/main/release-notes/10.0/supported-os.md _replacements.Add(input => input.Replace("\0", " ", StringComparison.Ordinal)); } @@ -56,10 +57,10 @@ static Column () public string FullValue { - get => _fullValue; + get; set { - _fullValue = value; + field = value; var temp = FullValue; @@ -80,6 +81,26 @@ public string FullValue #region Public methods + /// + /// Configures the maximum display length for all Column instances. + /// This is separate from the reader-level MaxLineLength. + /// + /// Maximum length for displayed content. Must be at least 1000. + public static void SetMaxDisplayLength (int maxLength) + { + if (maxLength < 1000) + { + throw new ArgumentOutOfRangeException(nameof(maxLength), "Maximum display length must be at least 1000 characters."); + } + + _maxDisplayLength = maxLength; + } + + /// + /// Gets the current maximum display length setting. + /// + public static int GetMaxDisplayLength () => _maxDisplayLength; + public static Column[] CreateColumns (int count, IColumnizedLogLine parent) { return CreateColumns(count, parent, string.Empty); diff --git a/src/LogExpert.Core/Classes/Log/LogfileReader.cs b/src/LogExpert.Core/Classes/Log/LogfileReader.cs index bfd69e11..dea84a23 100644 --- a/src/LogExpert.Core/Classes/Log/LogfileReader.cs +++ b/src/LogExpert.Core/Classes/Log/LogfileReader.cs @@ -29,8 +29,13 @@ public class LogfileReader : IAutoLogLineColumnizerCallback, IDisposable private ReaderWriterLock _bufferListLock; private bool _contentDeleted; private int _currLineCount; + + private readonly int _maximumLineLength; + private ReaderWriterLock _disposeLock; + private EncodingOptions _encodingOptions; + private long _fileLength; private Task _garbageCollectorTask; private Task _monitorTask; @@ -50,20 +55,20 @@ public class LogfileReader : IAutoLogLineColumnizerCallback, IDisposable #region cTor /// Public constructor for single file. - public LogfileReader (string fileName, EncodingOptions encodingOptions, bool multiFile, int bufferCount, int linesPerBuffer, MultiFileOptions multiFileOptions, bool useNewReader, IPluginRegistry pluginRegistry) - : this([fileName], encodingOptions, multiFile, bufferCount, linesPerBuffer, multiFileOptions, useNewReader, pluginRegistry) + public LogfileReader (string fileName, EncodingOptions encodingOptions, bool multiFile, int bufferCount, int linesPerBuffer, MultiFileOptions multiFileOptions, bool useNewReader, IPluginRegistry pluginRegistry, int maximumLineLength) + : this([fileName], encodingOptions, multiFile, bufferCount, linesPerBuffer, multiFileOptions, useNewReader, pluginRegistry, maximumLineLength) { } /// Public constructor for multiple files. - public LogfileReader (string[] fileNames, EncodingOptions encodingOptions, int bufferCount, int linesPerBuffer, MultiFileOptions multiFileOptions, bool useNewReader, IPluginRegistry pluginRegistry) - : this(fileNames, encodingOptions, true, bufferCount, linesPerBuffer, multiFileOptions, useNewReader, pluginRegistry) + public LogfileReader (string[] fileNames, EncodingOptions encodingOptions, int bufferCount, int linesPerBuffer, MultiFileOptions multiFileOptions, bool useNewReader, IPluginRegistry pluginRegistry, int maximumLineLength) + : this(fileNames, encodingOptions, true, bufferCount, linesPerBuffer, multiFileOptions, useNewReader, pluginRegistry, maximumLineLength) { // In this overload, we assume multiFile is always true. } // Single private constructor that contains the common initialization logic. - private LogfileReader (string[] fileNames, EncodingOptions encodingOptions, bool multiFile, int bufferCount, int linesPerBuffer, MultiFileOptions multiFileOptions, bool useNewReader, IPluginRegistry pluginRegistry) + private LogfileReader (string[] fileNames, EncodingOptions encodingOptions, bool multiFile, int bufferCount, int linesPerBuffer, MultiFileOptions multiFileOptions, bool useNewReader, IPluginRegistry pluginRegistry, int maximumLineLength) { // Validate input: at least one file must be provided. if (fileNames == null || fileNames.Length < 1) @@ -71,6 +76,13 @@ private LogfileReader (string[] fileNames, EncodingOptions encodingOptions, bool throw new ArgumentException("Must provide at least one file.", nameof(fileNames)); } + //Set default maximum line length if invalid value provided. + if (maximumLineLength <= 0) + { + maximumLineLength = 500; + } + + _maximumLineLength = maximumLineLength; _useNewReader = useNewReader; EncodingOptions = encodingOptions; _max_buffers = bufferCount; @@ -1535,9 +1547,12 @@ private void FileChanged () private void FireChangeEvent () { - LogEventArgs args = new(); - args.PrevFileSize = FileSize; - args.PrevLineCount = LineCount; + LogEventArgs args = new() + { + PrevFileSize = FileSize, + PrevLineCount = LineCount + }; + var newSize = _fileLength; if (newSize < FileSize || _isDeleted) { @@ -1604,12 +1619,9 @@ private ILogStreamReader GetLogStreamReader (Stream stream, EncodingOptions enco private ILogStreamReader CreateLogStreamReader (Stream stream, EncodingOptions encodingOptions, bool useSystemReader) { - if (useSystemReader) - { - return new PositionAwareStreamReaderSystem(stream, encodingOptions); - } - - return new PositionAwareStreamReaderLegacy(stream, encodingOptions); + return useSystemReader + ? new PositionAwareStreamReaderSystem(stream, encodingOptions, _maximumLineLength) + : new PositionAwareStreamReaderLegacy(stream, encodingOptions, _maximumLineLength); } private bool ReadLine (ILogStreamReader reader, int lineNum, int realLineNum, out string outLine) diff --git a/src/LogExpert.Core/Classes/Log/PositionAwareStreamReaderBase.cs b/src/LogExpert.Core/Classes/Log/PositionAwareStreamReaderBase.cs index 27a9b30f..79240f96 100644 --- a/src/LogExpert.Core/Classes/Log/PositionAwareStreamReaderBase.cs +++ b/src/LogExpert.Core/Classes/Log/PositionAwareStreamReaderBase.cs @@ -8,8 +8,6 @@ public abstract class PositionAwareStreamReaderBase : LogStreamReaderBase { #region Fields - private const int MAX_LINE_LEN = 20000; - private static readonly Encoding[] _preambleEncodings = [Encoding.UTF8, Encoding.Unicode, Encoding.BigEndianUnicode, Encoding.UTF32]; private readonly BufferedStream _stream; @@ -24,10 +22,12 @@ public abstract class PositionAwareStreamReaderBase : LogStreamReaderBase #region cTor - protected PositionAwareStreamReaderBase (Stream stream, EncodingOptions encodingOptions) + protected PositionAwareStreamReaderBase (Stream stream, EncodingOptions encodingOptions, int maximumLineLength) { _stream = new BufferedStream(stream); + MaximumLineLength = maximumLineLength; + _preambleLength = DetectPreambleLengthAndEncoding(out var detectedEncoding); var usedEncoding = GetUsedEncoding(encodingOptions, detectedEncoding); @@ -61,7 +61,7 @@ public sealed override long Position _position = value; // +Encoding.GetPreamble().Length; // 1 //stream.Seek(pos, SeekOrigin.Begin); // 2 //stream.Seek(pos + Encoding.GetPreamble().Length, SeekOrigin.Begin); // 3 - _stream.Seek(_position + _preambleLength, SeekOrigin.Begin); // 4 + _ = _stream.Seek(_position + _preambleLength, SeekOrigin.Begin); // 4 ResetReader(); } @@ -71,8 +71,11 @@ public sealed override long Position public sealed override bool IsBufferComplete => true; - //Refactor this needs to be given and should not be added like this - protected static int MaxLineLen => 500;//ConfigManager.Settings.Preferences.MaxLineLength; + protected static int MaximumLineLength + { + get => field; + private set => field = value; + } #endregion @@ -89,7 +92,7 @@ protected override void Dispose (bool disposing) _stream.Dispose(); _reader.Dispose(); IsDisposed = true; -} + } } //TODO This is unsafe and should be refactored @@ -188,21 +191,14 @@ private int DetectPreambleLengthAndEncoding (out Encoding detectedEncoding) return 0; } - private Encoding GetUsedEncoding (EncodingOptions encodingOptions, Encoding detectedEncoding) + private static Encoding GetUsedEncoding (EncodingOptions encodingOptions, Encoding detectedEncoding) { - if (encodingOptions.Encoding != null) - { - return encodingOptions.Encoding; - } - - if (detectedEncoding != null) - { - return detectedEncoding; - } - - return encodingOptions.DefaultEncoding ?? Encoding.Default; + return encodingOptions.Encoding ?? + detectedEncoding ?? + encodingOptions.DefaultEncoding ?? + Encoding.Default; } - private int GetPosIncPrecomputed (Encoding usedEncoding) + private static int GetPosIncPrecomputed (Encoding usedEncoding) { switch (usedEncoding) { diff --git a/src/LogExpert.Core/Classes/Log/PositionAwareStreamReaderLegacy.cs b/src/LogExpert.Core/Classes/Log/PositionAwareStreamReaderLegacy.cs index daaa97c3..d4149460 100644 --- a/src/LogExpert.Core/Classes/Log/PositionAwareStreamReaderLegacy.cs +++ b/src/LogExpert.Core/Classes/Log/PositionAwareStreamReaderLegacy.cs @@ -2,11 +2,11 @@ namespace LogExpert.Core.Classes.Log; -public class PositionAwareStreamReaderLegacy : PositionAwareStreamReaderBase +public class PositionAwareStreamReaderLegacy (Stream stream, EncodingOptions encodingOptions, int maximumLineLength) : PositionAwareStreamReaderBase(stream, encodingOptions, maximumLineLength) { #region Fields - private readonly char[] _charBuffer = new char[MaxLineLen]; + private readonly char[] _charBuffer = new char[maximumLineLength]; private int _charBufferPos; private bool _crDetect; @@ -14,19 +14,13 @@ public class PositionAwareStreamReaderLegacy : PositionAwareStreamReaderBase public override bool IsDisposed { get; protected set; } #endregion - #region cTor - public PositionAwareStreamReaderLegacy(Stream stream, EncodingOptions encodingOptions) : base(stream, encodingOptions) - { - - } - #endregion #region Public methods - public override string ReadLine() + public override string ReadLine () { int readInt; @@ -77,7 +71,7 @@ public override string ReadLine() return result; } - protected override void ResetReader() + protected override void ResetReader () { ResetCharBufferPos(); @@ -88,22 +82,22 @@ protected override void ResetReader() #region Private Methods - private string GetLineAndResetCharBufferPos() + private string GetLineAndResetCharBufferPos () { string result = new(_charBuffer, 0, _charBufferPos); ResetCharBufferPos(); return result; } - private void AppendToCharBuffer(char readChar) + private void AppendToCharBuffer (char readChar) { - if (_charBufferPos < MaxLineLen) + if (_charBufferPos < MaximumLineLength) { _charBuffer[_charBufferPos++] = readChar; } } - private void ResetCharBufferPos() + private void ResetCharBufferPos () { _charBufferPos = 0; } diff --git a/src/LogExpert.Core/Classes/Log/PositionAwareStreamReaderSystem.cs b/src/LogExpert.Core/Classes/Log/PositionAwareStreamReaderSystem.cs index 0f11cb60..5163c534 100644 --- a/src/LogExpert.Core/Classes/Log/PositionAwareStreamReaderSystem.cs +++ b/src/LogExpert.Core/Classes/Log/PositionAwareStreamReaderSystem.cs @@ -8,7 +8,7 @@ namespace LogExpert.Core.Classes.Log; /// UTF-8 handling is a bit slower, because after reading a character the byte length of the character must be determined. /// Lines are read char-by-char. StreamReader.ReadLine() is not used because StreamReader cannot tell a file position. /// -public class PositionAwareStreamReaderSystem : PositionAwareStreamReaderBase +public class PositionAwareStreamReaderSystem (Stream stream, EncodingOptions encodingOptions, int maximumLineLength) : PositionAwareStreamReaderBase(stream, encodingOptions, maximumLineLength) { #region Fields @@ -23,16 +23,11 @@ public class PositionAwareStreamReaderSystem : PositionAwareStreamReaderBase #region cTor - public PositionAwareStreamReaderSystem(Stream stream, EncodingOptions encodingOptions) : base(stream, encodingOptions) - { - - } - #endregion #region Public methods - public override string ReadLine() + public override string ReadLine () { var reader = GetStreamReader(); @@ -47,9 +42,9 @@ public override string ReadLine() { MovePosition(Encoding.GetByteCount(line) + _newLineSequenceLength); - if (line.Length > MaxLineLen) + if (line.Length > MaximumLineLength) { - line = line.Remove(MaxLineLen); + line = line[..MaximumLineLength]; } } @@ -60,7 +55,7 @@ public override string ReadLine() #region Private Methods - private int GuessNewLineSequenceLength(StreamReader reader) + private int GuessNewLineSequenceLength (StreamReader reader) { var currentPos = Position; diff --git a/src/LogExpert.Core/Config/Preferences.cs b/src/LogExpert.Core/Config/Preferences.cs index 97c8d230..08ed7be7 100644 --- a/src/LogExpert.Core/Config/Preferences.cs +++ b/src/LogExpert.Core/Config/Preferences.cs @@ -14,8 +14,31 @@ public class Preferences public bool ShowErrorMessageAllowOnlyOneInstances { get; set; } + /// + /// Maximum length of lines that can be read from log files at the reader level. + /// Lines exceeding this length will be truncated during file reading operations. + /// This setting protects against memory issues and performance degradation from extremely long lines. + /// + /// + /// + /// This property controls line truncation at the I/O reader level before lines are processed by columnizers. + /// It is implemented in + /// and . + /// + /// + /// Related property: controls display-level truncation in UI columns, + /// which must not exceed this value. Default is 20000 characters. + /// + /// public int MaxLineLength { get; set; } = 20000; + /// + /// Maximum length of text displayed in columns before truncation with "...". + /// This is separate from which controls reader-level line reading. + /// Must not exceed . Default is 20000 characters. + /// + public int MaxDisplayLength { get; set; } = 20000; + public bool AllowOnlyOneInstance { get; set; } public bool AskForClose { get; set; } diff --git a/src/LogExpert.Tests/BufferShiftTest.cs b/src/LogExpert.Tests/BufferShiftTest.cs index ba37e61e..dceb9df4 100644 --- a/src/LogExpert.Tests/BufferShiftTest.cs +++ b/src/LogExpert.Tests/BufferShiftTest.cs @@ -41,8 +41,8 @@ public void TestShiftBuffers1 () Encoding = Encoding.Default }; - _ = LogExpert.PluginRegistry.PluginRegistry.Create(TestDirectory.FullName, 500); - LogfileReader reader = new(files.Last.Value, encodingOptions, true, 40, 50, options, false, LogExpert.PluginRegistry.PluginRegistry.Instance); + _ = PluginRegistry.PluginRegistry.Create(TestDirectory.FullName, 500); + LogfileReader reader = new(files.Last.Value, encodingOptions, true, 40, 50, options, false, PluginRegistry.PluginRegistry.Instance, 500); reader.ReadFiles(); var lil = reader.GetLogFileInfoList(); diff --git a/src/LogExpert.Tests/CSVColumnizerTest.cs b/src/LogExpert.Tests/CSVColumnizerTest.cs index 2a6f4dcb..3e16fd55 100644 --- a/src/LogExpert.Tests/CSVColumnizerTest.cs +++ b/src/LogExpert.Tests/CSVColumnizerTest.cs @@ -15,7 +15,7 @@ public void Instantiat_CSVFile_BuildCorrectColumnizer (string filename, string[] { CsvColumnizer.CsvColumnizer csvColumnizer = new(); var path = Path.Join(AppDomain.CurrentDomain.BaseDirectory, filename); - LogfileReader reader = new(path, new EncodingOptions(), true, 40, 50, new MultiFileOptions(), false, LogExpert.PluginRegistry.PluginRegistry.Instance); + LogfileReader reader = new(path, new EncodingOptions(), true, 40, 50, new MultiFileOptions(), false, PluginRegistry.PluginRegistry.Instance, 500); reader.ReadFiles(); var line = reader.GetLogLine(0); IColumnizedLogLine logline = new ColumnizedLogLine(); diff --git a/src/LogExpert.Tests/ColumnizerPickerTest.cs b/src/LogExpert.Tests/ColumnizerPickerTest.cs index 3a26e9b9..d5257eb8 100644 --- a/src/LogExpert.Tests/ColumnizerPickerTest.cs +++ b/src/LogExpert.Tests/ColumnizerPickerTest.cs @@ -66,7 +66,7 @@ public void FindColumnizer_ReturnCorrectColumnizer (string expectedColumnizerNam public void FindReplacementForAutoColumnizer_ValidTextFile_ReturnCorrectColumnizer (string fileName, Type columnizerType) { var path = Path.Join(AppDomain.CurrentDomain.BaseDirectory, fileName); - LogfileReader reader = new(path, new EncodingOptions(), true, 40, 50, new MultiFileOptions(), false, PluginRegistry.PluginRegistry.Instance); + LogfileReader reader = new(path, new EncodingOptions(), true, 40, 50, new MultiFileOptions(), false, PluginRegistry.PluginRegistry.Instance, 500); reader.ReadFiles(); Mock autoColumnizer = new(); diff --git a/src/LogExpert.Tests/JsonColumnizerTest.cs b/src/LogExpert.Tests/JsonColumnizerTest.cs index 392cf40b..d1bc9295 100644 --- a/src/LogExpert.Tests/JsonColumnizerTest.cs +++ b/src/LogExpert.Tests/JsonColumnizerTest.cs @@ -13,7 +13,7 @@ public void GetColumnNames_HappyFile_ColumnNameMatches (string fileName, string { var jsonColumnizer = new JsonColumnizer.JsonColumnizer(); var path = Path.Join(AppDomain.CurrentDomain.BaseDirectory, fileName); - LogfileReader reader = new(path, new EncodingOptions(), true, 40, 50, new MultiFileOptions(), false, LogExpert.PluginRegistry.PluginRegistry.Instance); + LogfileReader reader = new(path, new EncodingOptions(), true, 40, 50, new MultiFileOptions(), false, PluginRegistry.PluginRegistry.Instance, 500); reader.ReadFiles(); var line = reader.GetLogLine(0); diff --git a/src/LogExpert.Tests/JsonCompactColumnizerTest.cs b/src/LogExpert.Tests/JsonCompactColumnizerTest.cs index 32b49137..7b6864e9 100644 --- a/src/LogExpert.Tests/JsonCompactColumnizerTest.cs +++ b/src/LogExpert.Tests/JsonCompactColumnizerTest.cs @@ -16,7 +16,7 @@ public void GetPriority_HappyFile_PriorityMatches (string fileName, Priority pri { var jsonCompactColumnizer = new JsonColumnizer.JsonCompactColumnizer(); var path = Path.Join(AppDomain.CurrentDomain.BaseDirectory, fileName); - LogfileReader logFileReader = new(path, new EncodingOptions(), true, 40, 50, new MultiFileOptions(), false, LogExpert.PluginRegistry.PluginRegistry.Instance); + LogfileReader logFileReader = new(path, new EncodingOptions(), true, 40, 50, new MultiFileOptions(), false, PluginRegistry.PluginRegistry.Instance, 500); logFileReader.ReadFiles(); List loglines = [ diff --git a/src/LogExpert.Tests/LocalFileSystemTest.cs b/src/LogExpert.Tests/LocalFileSystemTest.cs index 185fee66..51424fca 100644 --- a/src/LogExpert.Tests/LocalFileSystemTest.cs +++ b/src/LogExpert.Tests/LocalFileSystemTest.cs @@ -36,7 +36,7 @@ public void TestUriHandle() [Test] public void TestUriToFileStream() { - var dInfo = Directory.CreateDirectory(RolloverHandlerTest.TEST_DIR_NAME); + var dInfo = Directory.CreateDirectory(TEST_DIR_NAME); var fullName = CreateFile(dInfo, "test.log"); LocalFileSystem fs = new(); diff --git a/src/LogExpert.Tests/LogStreamReaderTest.cs b/src/LogExpert.Tests/LogStreamReaderTest.cs index 4ee9dd35..efc0c383 100644 --- a/src/LogExpert.Tests/LogStreamReaderTest.cs +++ b/src/LogExpert.Tests/LogStreamReaderTest.cs @@ -1,11 +1,10 @@ -using LogExpert.Core.Classes.Log; +using System.Text; + +using LogExpert.Core.Classes.Log; using LogExpert.Core.Entities; using NUnit.Framework; -using System.IO; -using System.Text; - namespace LogExpert.Tests; [TestFixture] @@ -18,10 +17,10 @@ public class LogStreamReaderTest [TestCase("Line 1\r\nLine 2\r\nLine 3\r\n", 3)] [TestCase("Line 1\rLine 2\rLine 3", 3)] [TestCase("Line 1\rLine 2\rLine 3\r", 3)] - public void ReadLinesWithSystemNewLine(string text, int expectedLines) + public void ReadLinesWithSystemNewLine (string text, int expectedLines) { using var stream = new MemoryStream(Encoding.ASCII.GetBytes(text)); - using var reader = new PositionAwareStreamReaderSystem(stream, new EncodingOptions()); + using var reader = new PositionAwareStreamReaderSystem(stream, new EncodingOptions(), 500); var lineCount = 0; while (true) { @@ -33,7 +32,7 @@ public void ReadLinesWithSystemNewLine(string text, int expectedLines) lineCount += 1; - Assert.That(line.StartsWith($"Line {lineCount}"), $"Invalid line: {line}"); + Assert.That(line.StartsWith($"Line {lineCount}", StringComparison.OrdinalIgnoreCase), $"Invalid line: {line}"); } Assert.That(expectedLines, Is.EqualTo(lineCount), $"Unexpected lines:\n{text}"); @@ -43,10 +42,10 @@ public void ReadLinesWithSystemNewLine(string text, int expectedLines) [TestCase("\n\n\n", 3)] [TestCase("\r\n\r\n\r\n", 3)] [TestCase("\r\r\r", 3)] - public void CountLinesWithSystemNewLine(string text, int expectedLines) + public void CountLinesWithSystemNewLine (string text, int expectedLines) { using var stream = new MemoryStream(Encoding.ASCII.GetBytes(text)); - using var reader = new PositionAwareStreamReaderSystem(stream, new EncodingOptions()); + using var reader = new PositionAwareStreamReaderSystem(stream, new EncodingOptions(), 500); var lineCount = 0; while (reader.ReadLine() != null) { @@ -63,45 +62,41 @@ public void CountLinesWithSystemNewLine(string text, int expectedLines) [TestCase("Line 1\r\nLine 2\r\nLine 3\r\n", 3)] [TestCase("Line 1\rLine 2\rLine 3", 3)] [TestCase("Line 1\rLine 2\rLine 3\r", 3)] - public void ReadLinesWithLegacyNewLine(string text, int expectedLines) + public void ReadLinesWithLegacyNewLine (string text, int expectedLines) { - using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(text))) - using (var reader = new PositionAwareStreamReaderLegacy(stream, new EncodingOptions())) + using var stream = new MemoryStream(Encoding.ASCII.GetBytes(text)); + using var reader = new PositionAwareStreamReaderLegacy(stream, new EncodingOptions(), 500); + var lineCount = 0; + while (true) { - var lineCount = 0; - while (true) + var line = reader.ReadLine(); + if (line == null) { - var line = reader.ReadLine(); - if (line == null) - { - break; - } - - lineCount += 1; - - Assert.That(line.StartsWith($"Line {lineCount}"), $"Invalid line: {line}"); + break; } - Assert.That(expectedLines, Is.EqualTo(lineCount), $"Unexpected lines:\n{text}"); + lineCount += 1; + + Assert.That(line.StartsWith($"Line {lineCount}", StringComparison.OrdinalIgnoreCase), $"Invalid line: {line}"); } + + Assert.That(expectedLines, Is.EqualTo(lineCount), $"Unexpected lines:\n{text}"); } [Test] [TestCase("\n\n\n", 3)] [TestCase("\r\n\r\n\r\n", 3)] [TestCase("\r\r\r", 3)] - public void CountLinesWithLegacyNewLine(string text, int expectedLines) + public void CountLinesWithLegacyNewLine (string text, int expectedLines) { - using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(text))) - using (var reader = new PositionAwareStreamReaderLegacy(stream, new EncodingOptions())) + using var stream = new MemoryStream(Encoding.ASCII.GetBytes(text)); + using var reader = new PositionAwareStreamReaderLegacy(stream, new EncodingOptions(), 500); + var lineCount = 0; + while (reader.ReadLine() != null) { - var lineCount = 0; - while (reader.ReadLine() != null) - { - lineCount += 1; - } + lineCount += 1; + } - Assert.That(expectedLines, Is.EqualTo(lineCount), $"Unexpected lines:\n{text}"); - } + Assert.That(expectedLines, Is.EqualTo(lineCount), $"Unexpected lines:\n{text}"); } } diff --git a/src/LogExpert.Tests/ReaderTest.cs b/src/LogExpert.Tests/ReaderTest.cs index 98367143..d55b4a03 100644 --- a/src/LogExpert.Tests/ReaderTest.cs +++ b/src/LogExpert.Tests/ReaderTest.cs @@ -1,38 +1,38 @@ -using LogExpert.Core.Classes.Log; +using System.Text; + +using LogExpert.Core.Classes.Log; using LogExpert.Core.Entities; using LogExpert.Core.Interface; using NUnit.Framework; -using System; -using System.IO; -using System.Text; - namespace LogExpert.Tests; [TestFixture] internal class ReaderTest { [TearDown] - public void TearDown() + public void TearDown () { } [OneTimeSetUp] - public void Boot() + public void Boot () { } - private void CompareReaderImplementationsInternal(string fileName, Encoding enc, int maxPosition) + private void CompareReaderImplementationsInternal (string fileName, Encoding enc, int maxPosition) { var path = Environment.CurrentDirectory + "\\data\\"; - EncodingOptions encOpts = new(); - encOpts.Encoding = enc; + EncodingOptions encOpts = new() + { + Encoding = enc + }; using Stream s1 = new FileStream(path + fileName, FileMode.Open, FileAccess.Read); using Stream s2 = new FileStream(path + fileName, FileMode.Open, FileAccess.Read); - using ILogStreamReader r1 = new PositionAwareStreamReaderLegacy(s1, encOpts); - using ILogStreamReader r2 = new PositionAwareStreamReaderSystem(s2, encOpts); + using ILogStreamReader r1 = new PositionAwareStreamReaderLegacy(s1, encOpts, 500); + using ILogStreamReader r2 = new PositionAwareStreamReaderSystem(s2, encOpts, 500); for (var lineNum = 0; ; lineNum++) { var line1 = r1.ReadLine(); diff --git a/src/LogExpert.Tests/RolloverHandlerTest.cs b/src/LogExpert.Tests/RolloverHandlerTest.cs index c7b7fa23..6a178848 100644 --- a/src/LogExpert.Tests/RolloverHandlerTest.cs +++ b/src/LogExpert.Tests/RolloverHandlerTest.cs @@ -23,7 +23,7 @@ public void TestFilenameListWithAppendedIndex (string format, int retries) ILogFileInfo info = new LogFileInfo(new Uri(firstFile)); RolloverFilenameHandler handler = new(info, options); - var fileList = handler.GetNameList(LogExpert.PluginRegistry.PluginRegistry.Instance); + var fileList = handler.GetNameList(PluginRegistry.PluginRegistry.Instance); Assert.That(fileList, Is.EqualTo(files)); @@ -44,7 +44,7 @@ public void TestFilenameListWithDate (string format, int retries) ILogFileInfo info = new LogFileInfo(new Uri(firstFile)); RolloverFilenameHandler handler = new(info, options); - var fileList = handler.GetNameList(LogExpert.PluginRegistry.PluginRegistry.Instance); + var fileList = handler.GetNameList(PluginRegistry.PluginRegistry.Instance); Assert.That(fileList, Is.EqualTo(files)); diff --git a/src/LogExpert.Tests/SquareBracketColumnizerTest.cs b/src/LogExpert.Tests/SquareBracketColumnizerTest.cs index ea1efe33..cedda75e 100644 --- a/src/LogExpert.Tests/SquareBracketColumnizerTest.cs +++ b/src/LogExpert.Tests/SquareBracketColumnizerTest.cs @@ -18,7 +18,7 @@ public void GetPriority_HappyFile_ColumnCountMatches (string fileName, int count SquareBracketColumnizer squareBracketColumnizer = new(); var path = Path.Join(AppDomain.CurrentDomain.BaseDirectory, fileName); - LogfileReader logFileReader = new(path, new EncodingOptions(), true, 40, 50, new MultiFileOptions(), false, LogExpert.PluginRegistry.PluginRegistry.Instance); + LogfileReader logFileReader = new(path, new EncodingOptions(), true, 40, 50, new MultiFileOptions(), false, PluginRegistry.PluginRegistry.Instance, 500); logFileReader.ReadFiles(); List loglines = [ @@ -35,7 +35,7 @@ public void GetPriority_HappyFile_ColumnCountMatches (string fileName, int count logFileReader.GetLogLine(400) ]; - squareBracketColumnizer.GetPriority(path, loglines); + _ = squareBracketColumnizer.GetPriority(path, loglines); Assert.That(count, Is.EqualTo(squareBracketColumnizer.GetColumnCount())); } diff --git a/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs b/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs index 317290c4..d65a86f8 100644 --- a/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs +++ b/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs @@ -6129,7 +6129,7 @@ public void LoadFile (string fileName, EncodingOptions encodingOptions) try { - _logFileReader = new(fileName, EncodingOptions, IsMultiFile, Preferences.BufferCount, Preferences.LinesPerBuffer, _multiFileOptions, !Preferences.UseLegacyReader, PluginRegistry.PluginRegistry.Instance); + _logFileReader = new(fileName, EncodingOptions, IsMultiFile, Preferences.BufferCount, Preferences.LinesPerBuffer, _multiFileOptions, !Preferences.UseLegacyReader, PluginRegistry.PluginRegistry.Instance, ConfigManager.Instance.Settings.Preferences.MaxLineLength); } catch (LogFileException lfe) { @@ -6192,7 +6192,7 @@ public void LoadFilesAsMulti (string[] fileNames, EncodingOptions encodingOption EncodingOptions = encodingOptions; _columnCache = new ColumnCache(); - _logFileReader = new(fileNames, EncodingOptions, Preferences.BufferCount, Preferences.LinesPerBuffer, _multiFileOptions, !Preferences.UseLegacyReader, PluginRegistry.PluginRegistry.Instance); + _logFileReader = new(fileNames, EncodingOptions, Preferences.BufferCount, Preferences.LinesPerBuffer, _multiFileOptions, !Preferences.UseLegacyReader, PluginRegistry.PluginRegistry.Instance, ConfigManager.Instance.Settings.Preferences.MaxLineLength); RegisterLogFileReaderEvents(); _logFileReader.StartMonitoring(); diff --git a/src/LogExpert.UI/Dialogs/LogTabWindow/LogTabWindow.cs b/src/LogExpert.UI/Dialogs/LogTabWindow/LogTabWindow.cs index be35201d..8f1ca879 100644 --- a/src/LogExpert.UI/Dialogs/LogTabWindow/LogTabWindow.cs +++ b/src/LogExpert.UI/Dialogs/LogTabWindow/LogTabWindow.cs @@ -94,6 +94,8 @@ public LogTabWindow (string[] fileNames, int instanceNumber, bool showInstanceNu InitializeComponent(); + ConfigureDockPanel(); + ApplyTextResources(); ConfigManager = configManager; @@ -288,6 +290,73 @@ public LogWindow.LogWindow AddTempFileTab (string fileName, string title) return AddFileTab(fileName, true, title, false, null); } + private void ConfigureDockPanel () + { + var autoHideStripSkin1 = new AutoHideStripSkin(); + var dockPanelGradient1 = new DockPanelGradient(); + var tabGradient1 = new TabGradient(); + var dockPaneStripSkin1 = new DockPaneStripSkin(); + var dockPaneStripGradient1 = new DockPaneStripGradient(); + var tabGradient2 = new TabGradient(); + var dockPanelGradient2 = new DockPanelGradient(); + var tabGradient3 = new TabGradient(); + var dockPaneStripToolWindowGradient1 = new DockPaneStripToolWindowGradient(); + var tabGradient4 = new TabGradient(); + var tabGradient5 = new TabGradient(); + var dockPanelGradient3 = new DockPanelGradient(); + var tabGradient6 = new TabGradient(); + var tabGradient7 = new TabGradient(); + + dockPanelGradient1.EndColor = SystemColors.Control; + dockPanelGradient1.StartColor = SystemColors.Control; + autoHideStripSkin1.DockStripGradient = dockPanelGradient1; + tabGradient1.EndColor = SystemColors.Control; + tabGradient1.StartColor = SystemColors.Control; + tabGradient1.TextColor = SystemColors.ControlText; + autoHideStripSkin1.TabGradient = tabGradient1; + autoHideStripSkin1.TextFont = new System.Drawing.Font("Segoe UI", 9F); + tabGradient2.EndColor = SystemColors.Control; + tabGradient2.StartColor = SystemColors.Control; + tabGradient2.TextColor = SystemColors.ControlText; + dockPaneStripGradient1.ActiveTabGradient = tabGradient2; + dockPanelGradient2.EndColor = SystemColors.Control; + dockPanelGradient2.StartColor = SystemColors.Control; + dockPaneStripGradient1.DockStripGradient = dockPanelGradient2; + tabGradient3.EndColor = SystemColors.ControlLight; + tabGradient3.StartColor = SystemColors.ControlLight; + tabGradient3.TextColor = SystemColors.ControlText; + dockPaneStripGradient1.InactiveTabGradient = tabGradient3; + dockPaneStripSkin1.DocumentGradient = dockPaneStripGradient1; + dockPaneStripSkin1.TextFont = new Font("Segoe UI", 9F); + tabGradient4.EndColor = SystemColors.ActiveCaption; + tabGradient4.LinearGradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical; + tabGradient4.StartColor = SystemColors.GradientActiveCaption; + tabGradient4.TextColor = SystemColors.ActiveCaptionText; + dockPaneStripToolWindowGradient1.ActiveCaptionGradient = tabGradient4; + tabGradient5.EndColor = SystemColors.Control; + tabGradient5.StartColor = SystemColors.Control; + tabGradient5.TextColor = SystemColors.ControlText; + dockPaneStripToolWindowGradient1.ActiveTabGradient = tabGradient5; + dockPanelGradient3.EndColor = SystemColors.ControlLight; + dockPanelGradient3.StartColor = SystemColors.ControlLight; + dockPaneStripToolWindowGradient1.DockStripGradient = dockPanelGradient3; + tabGradient6.EndColor = SystemColors.InactiveCaption; + tabGradient6.LinearGradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical; + tabGradient6.StartColor = SystemColors.GradientInactiveCaption; + tabGradient6.TextColor = SystemColors.InactiveCaptionText; + dockPaneStripToolWindowGradient1.InactiveCaptionGradient = tabGradient6; + tabGradient7.EndColor = Color.Transparent; + tabGradient7.StartColor = Color.Transparent; + tabGradient7.TextColor = SystemColors.Control; + dockPaneStripToolWindowGradient1.InactiveTabGradient = tabGradient7; + dockPaneStripSkin1.ToolWindowGradient = dockPaneStripToolWindowGradient1; + dockPanel.Theme = new VS2015LightTheme(); + dockPanel.Theme.Skin.DockPaneStripSkin = dockPaneStripSkin1; + dockPanel.Theme.Skin.AutoHideStripSkin = autoHideStripSkin1; + dockPanel.ActiveAutoHideContent = null; + } + + private void ApplyTextResources () { diff --git a/src/LogExpert.UI/Dialogs/SettingsDialog.Designer.cs b/src/LogExpert.UI/Dialogs/SettingsDialog.Designer.cs index 2f853806..f4abe002 100644 --- a/src/LogExpert.UI/Dialogs/SettingsDialog.Designer.cs +++ b/src/LogExpert.UI/Dialogs/SettingsDialog.Designer.cs @@ -29,11 +29,14 @@ protected override void Dispose(bool disposing) private void InitializeComponent () { components = new System.ComponentModel.Container(); + var resources = new System.ComponentModel.ComponentResourceManager(typeof(SettingsDialog)); tabControlSettings = new TabControl(); tabPageViewSettings = new TabPage(); labelWarningMaximumLineLength = new Label(); upDownMaximumLineLength = new NumericUpDown(); labelMaximumLineLength = new Label(); + upDownMaxDisplayLength = new NumericUpDown(); + labelMaxDisplayLength = new Label(); upDownMaximumFilterEntriesDisplayed = new NumericUpDown(); labelMaximumFilterEntriesDisplayed = new Label(); upDownMaximumFilterEntries = new NumericUpDown(); @@ -158,6 +161,7 @@ private void InitializeComponent () tabControlSettings.SuspendLayout(); tabPageViewSettings.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)upDownMaximumLineLength).BeginInit(); + ((System.ComponentModel.ISupportInitialize)upDownMaxDisplayLength).BeginInit(); ((System.ComponentModel.ISupportInitialize)upDownMaximumFilterEntriesDisplayed).BeginInit(); ((System.ComponentModel.ISupportInitialize)upDownMaximumFilterEntries).BeginInit(); groupBoxMisc.SuspendLayout(); @@ -216,6 +220,8 @@ private void InitializeComponent () tabPageViewSettings.Controls.Add(labelWarningMaximumLineLength); tabPageViewSettings.Controls.Add(upDownMaximumLineLength); tabPageViewSettings.Controls.Add(labelMaximumLineLength); + tabPageViewSettings.Controls.Add(upDownMaxDisplayLength); + tabPageViewSettings.Controls.Add(labelMaxDisplayLength); tabPageViewSettings.Controls.Add(upDownMaximumFilterEntriesDisplayed); tabPageViewSettings.Controls.Add(labelMaximumFilterEntriesDisplayed); tabPageViewSettings.Controls.Add(upDownMaximumFilterEntries); @@ -237,7 +243,7 @@ private void InitializeComponent () // labelWarningMaximumLineLength // labelWarningMaximumLineLength.AutoSize = true; - labelWarningMaximumLineLength.Location = new Point(446, 118); + labelWarningMaximumLineLength.Location = new Point(446, 101); labelWarningMaximumLineLength.Name = "labelWarningMaximumLineLength"; labelWarningMaximumLineLength.Size = new Size(483, 15); labelWarningMaximumLineLength.TabIndex = 16; @@ -245,7 +251,7 @@ private void InitializeComponent () // // upDownMaximumLineLength // - upDownMaximumLineLength.Location = new Point(762, 138); + upDownMaximumLineLength.Location = new Point(762, 121); upDownMaximumLineLength.Margin = new Padding(4, 5, 4, 5); upDownMaximumLineLength.Maximum = new decimal(new int[] { 1000000, 0, 0, 0 }); upDownMaximumLineLength.Minimum = new decimal(new int[] { 20000, 0, 0, 0 }); @@ -253,20 +259,43 @@ private void InitializeComponent () upDownMaximumLineLength.Size = new Size(106, 23); upDownMaximumLineLength.TabIndex = 15; upDownMaximumLineLength.Value = new decimal(new int[] { 20000, 0, 0, 0 }); + upDownMaximumLineLength.ValueChanged += OnUpDownMaximumLineLengthValueChanged; // // labelMaximumLineLength // labelMaximumLineLength.AutoSize = true; - labelMaximumLineLength.Location = new Point(467, 140); + labelMaximumLineLength.Location = new Point(467, 123); labelMaximumLineLength.Margin = new Padding(4, 0, 4, 0); labelMaximumLineLength.Name = "labelMaximumLineLength"; labelMaximumLineLength.Size = new Size(218, 15); labelMaximumLineLength.TabIndex = 14; labelMaximumLineLength.Text = "Maximum Line Length (restart required)"; // + // upDownMaxDisplayLength + // + upDownMaxDisplayLength.Location = new Point(762, 149); + upDownMaxDisplayLength.Margin = new Padding(4, 5, 4, 5); + upDownMaxDisplayLength.Maximum = new decimal(new int[] { 1000000, 0, 0, 0 }); + upDownMaxDisplayLength.Minimum = new decimal(new int[] { 1000, 0, 0, 0 }); + upDownMaxDisplayLength.Name = "upDownMaxDisplayLength"; + upDownMaxDisplayLength.Size = new Size(106, 23); + upDownMaxDisplayLength.TabIndex = 18; + upDownMaxDisplayLength.Value = new decimal(new int[] { 20000, 0, 0, 0 }); + upDownMaxDisplayLength.ValueChanged += OnUpDownMaxDisplayLengthValueChanged; + // + // labelMaxDisplayLength + // + labelMaxDisplayLength.AutoSize = true; + labelMaxDisplayLength.Location = new Point(467, 151); + labelMaxDisplayLength.Margin = new Padding(4, 0, 4, 0); + labelMaxDisplayLength.Name = "labelMaxDisplayLength"; + labelMaxDisplayLength.Size = new Size(234, 15); + labelMaxDisplayLength.TabIndex = 17; + labelMaxDisplayLength.Text = "Maximum Display Length (restart required)"; + // // upDownMaximumFilterEntriesDisplayed // - upDownMaximumFilterEntriesDisplayed.Location = new Point(762, 86); + upDownMaximumFilterEntriesDisplayed.Location = new Point(762, 69); upDownMaximumFilterEntriesDisplayed.Margin = new Padding(4, 5, 4, 5); upDownMaximumFilterEntriesDisplayed.Maximum = new decimal(new int[] { 30, 0, 0, 0 }); upDownMaximumFilterEntriesDisplayed.Minimum = new decimal(new int[] { 10, 0, 0, 0 }); @@ -278,7 +307,7 @@ private void InitializeComponent () // labelMaximumFilterEntriesDisplayed // labelMaximumFilterEntriesDisplayed.AutoSize = true; - labelMaximumFilterEntriesDisplayed.Location = new Point(467, 88); + labelMaximumFilterEntriesDisplayed.Location = new Point(467, 71); labelMaximumFilterEntriesDisplayed.Margin = new Padding(4, 0, 4, 0); labelMaximumFilterEntriesDisplayed.Name = "labelMaximumFilterEntriesDisplayed"; labelMaximumFilterEntriesDisplayed.Size = new Size(180, 15); @@ -287,7 +316,7 @@ private void InitializeComponent () // // upDownMaximumFilterEntries // - upDownMaximumFilterEntries.Location = new Point(762, 59); + upDownMaximumFilterEntries.Location = new Point(762, 42); upDownMaximumFilterEntries.Margin = new Padding(4, 5, 4, 5); upDownMaximumFilterEntries.Minimum = new decimal(new int[] { 10, 0, 0, 0 }); upDownMaximumFilterEntries.Name = "upDownMaximumFilterEntries"; @@ -298,7 +327,7 @@ private void InitializeComponent () // labelMaximumFilterEntries // labelMaximumFilterEntries.AutoSize = true; - labelMaximumFilterEntries.Location = new Point(467, 61); + labelMaximumFilterEntries.Location = new Point(467, 44); labelMaximumFilterEntries.Margin = new Padding(4, 0, 4, 0); labelMaximumFilterEntries.Name = "labelMaximumFilterEntries"; labelMaximumFilterEntries.Size = new Size(127, 15); @@ -308,7 +337,7 @@ private void InitializeComponent () // labelDefaultEncoding // labelDefaultEncoding.AutoSize = true; - labelDefaultEncoding.Location = new Point(467, 34); + labelDefaultEncoding.Location = new Point(467, 17); labelDefaultEncoding.Margin = new Padding(4, 0, 4, 0); labelDefaultEncoding.Name = "labelDefaultEncoding"; labelDefaultEncoding.Size = new Size(98, 15); @@ -319,7 +348,7 @@ private void InitializeComponent () // comboBoxEncoding.DropDownStyle = ComboBoxStyle.DropDownList; comboBoxEncoding.FormattingEnabled = true; - comboBoxEncoding.Location = new Point(691, 26); + comboBoxEncoding.Location = new Point(691, 9); comboBoxEncoding.Margin = new Padding(4, 5, 4, 5); comboBoxEncoding.Name = "comboBoxEncoding"; comboBoxEncoding.Size = new Size(177, 23); @@ -1192,7 +1221,7 @@ private void InitializeComponent () labelNoteMultiFile.Name = "labelNoteMultiFile"; labelNoteMultiFile.Size = new Size(705, 82); labelNoteMultiFile.TabIndex = 1; - labelNoteMultiFile.Text = "Note: You can always load your logfiles as MultiFile automatically if the files names follow the MultiFile naming rule (, .1, .2, ...). Simply choose 'MultiFile' from the File menu after loading the first file."; + labelNoteMultiFile.Text = resources.GetString("labelNoteMultiFile.Text"); // // groupBoxWhenOpeningMultiFile // @@ -1275,7 +1304,6 @@ private void InitializeComponent () listBoxPlugin.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; listBoxPlugin.DisplayMember = "Text"; listBoxPlugin.FormattingEnabled = true; - listBoxPlugin.ItemHeight = 15; listBoxPlugin.Location = new Point(9, 29); listBoxPlugin.Margin = new Padding(4, 5, 4, 5); listBoxPlugin.Name = "listBoxPlugin"; @@ -1671,6 +1699,7 @@ private void InitializeComponent () tabPageViewSettings.ResumeLayout(false); tabPageViewSettings.PerformLayout(); ((System.ComponentModel.ISupportInitialize)upDownMaximumLineLength).EndInit(); + ((System.ComponentModel.ISupportInitialize)upDownMaxDisplayLength).EndInit(); ((System.ComponentModel.ISupportInitialize)upDownMaximumFilterEntriesDisplayed).EndInit(); ((System.ComponentModel.ISupportInitialize)upDownMaximumFilterEntries).EndInit(); groupBoxMisc.ResumeLayout(false); @@ -1847,6 +1876,8 @@ private void InitializeComponent () private System.Windows.Forms.NumericUpDown upDownMaximumLineLength; private System.Windows.Forms.Label labelMaximumLineLength; private System.Windows.Forms.Label labelWarningMaximumLineLength; + private System.Windows.Forms.NumericUpDown upDownMaxDisplayLength; + private System.Windows.Forms.Label labelMaxDisplayLength; private Label labelLanguage; private ComboBox comboBoxLanguage; } diff --git a/src/LogExpert.UI/Dialogs/SettingsDialog.cs b/src/LogExpert.UI/Dialogs/SettingsDialog.cs index 578be2a0..65c958ea 100644 --- a/src/LogExpert.UI/Dialogs/SettingsDialog.cs +++ b/src/LogExpert.UI/Dialogs/SettingsDialog.cs @@ -207,6 +207,10 @@ private void FillDialog () } upDownMaximumLineLength.Value = Preferences.MaxLineLength; + upDownMaxDisplayLength.Value = Preferences.MaxDisplayLength; + + // Ensure MaxDisplayLength doesn't exceed MaxLineLength + upDownMaxDisplayLength.Maximum = Math.Min(upDownMaxDisplayLength.Maximum, upDownMaximumLineLength.Value); upDownMaximumFilterEntriesDisplayed.Value = Preferences.MaximumFilterEntriesDisplayed; upDownMaximumFilterEntries.Value = Preferences.MaximumFilterEntries; @@ -759,6 +763,8 @@ private void OnBtnOkClick (object sender, EventArgs e) Preferences.MaximumFilterEntriesDisplayed = (int)upDownMaximumFilterEntriesDisplayed.Value; Preferences.ShowErrorMessageAllowOnlyOneInstances = checkBoxShowErrorMessageOnlyOneInstance.Checked; Preferences.DarkMode = checkBoxDarkMode.Checked; + Preferences.MaxLineLength = (int)upDownMaximumLineLength.Value; + Preferences.MaxDisplayLength = Math.Min((int)upDownMaxDisplayLength.Value, (int)upDownMaximumLineLength.Value); SavePluginSettings(); SaveHighlightMaskList(); @@ -1183,6 +1189,27 @@ or NotSupportedException } } + private void OnUpDownMaxDisplayLengthValueChanged (object sender, EventArgs e) + { + // Ensure MaxDisplayLength doesn't exceed MaxLineLength + if (upDownMaxDisplayLength.Value > upDownMaximumLineLength.Value) + { + upDownMaxDisplayLength.Value = upDownMaximumLineLength.Value; + } + } + + private void OnUpDownMaximumLineLengthValueChanged (object sender, EventArgs e) + { + // When MaxLineLength changes, update the maximum allowed for MaxDisplayLength + upDownMaxDisplayLength.Maximum = Math.Min(1000000, upDownMaximumLineLength.Value); + + // If current MaxDisplayLength exceeds new MaxLineLength, adjust it + if (upDownMaxDisplayLength.Value > upDownMaximumLineLength.Value) + { + upDownMaxDisplayLength.Value = upDownMaximumLineLength.Value; + } + } + #endregion #region Resources Map diff --git a/src/LogExpert.UI/Dialogs/SettingsDialog.resx b/src/LogExpert.UI/Dialogs/SettingsDialog.resx index dda79304..239344f9 100644 --- a/src/LogExpert.UI/Dialogs/SettingsDialog.resx +++ b/src/LogExpert.UI/Dialogs/SettingsDialog.resx @@ -123,4 +123,7 @@ 17, 17 + + Note: You can always load your logfiles as MultiFile automatically if the files names follow the MultiFile naming rule (<filename>, <filename>.1, <filename>.2, ...). Simply choose 'MultiFile' from the File menu after loading the first file. + \ No newline at end of file diff --git a/src/LogExpert/Program.cs b/src/LogExpert/Program.cs index 027b4b99..1319679f 100644 --- a/src/LogExpert/Program.cs +++ b/src/LogExpert/Program.cs @@ -99,6 +99,8 @@ private static void Main (string[] args) _ = PluginRegistry.PluginRegistry.Create(ConfigManager.Instance.ConfigDir, ConfigManager.Instance.Settings.Preferences.PollingInterval); + ColumnizerLib.Column.SetMaxDisplayLength(ConfigManager.Instance.Settings.Preferences.MaxDisplayLength); + var pId = Process.GetCurrentProcess().SessionId; try diff --git a/src/PluginRegistry/PluginHashGenerator.Generated.cs b/src/PluginRegistry/PluginHashGenerator.Generated.cs index b54362c1..39a3f0ca 100644 --- a/src/PluginRegistry/PluginHashGenerator.Generated.cs +++ b/src/PluginRegistry/PluginHashGenerator.Generated.cs @@ -10,7 +10,7 @@ public static partial class PluginValidator { /// /// Gets pre-calculated SHA256 hashes for built-in plugins. - /// Generated: 2025-11-20 14:33:29 UTC + /// Generated: 2025-11-21 20:28:40 UTC /// Configuration: Release /// Plugin count: 21 /// @@ -18,27 +18,27 @@ public static Dictionary GetBuiltInPluginHashes() { return new Dictionary(StringComparer.OrdinalIgnoreCase) { - ["AutoColumnizer.dll"] = "422DD1988815352F0A4B20706A6A78553908E6305CEC40B7B2395ECBE421F6FD", + ["AutoColumnizer.dll"] = "357B2D7DC39FBDF355092F47594DFB2DFA8E40AD6D762B6911273ED1205184C0", ["BouncyCastle.Cryptography.dll"] = "E5EEAF6D263C493619982FD3638E6135077311D08C961E1FE128F9107D29EBC6", ["BouncyCastle.Cryptography.dll (x86)"] = "E5EEAF6D263C493619982FD3638E6135077311D08C961E1FE128F9107D29EBC6", - ["CsvColumnizer.dll"] = "DABD8FB427F248335DA85D2498FEC864F0FD9F2BBE4B6E5AEEECB8BDD357A6D4", - ["CsvColumnizer.dll (x86)"] = "DABD8FB427F248335DA85D2498FEC864F0FD9F2BBE4B6E5AEEECB8BDD357A6D4", - ["DefaultPlugins.dll"] = "50D131F12FF290D1744B2C19ED8668D9A6485B44211B4FE6363F86A3455286D8", - ["FlashIconHighlighter.dll"] = "071159ED11942ED02AEB66189DB9722EE3346C41E56A2C0C4848312F8E379D3C", - ["GlassfishColumnizer.dll"] = "50C88BF529BA9E412B602775B802F18827C1233517B30FBC8235EDEB839B1FC4", - ["JsonColumnizer.dll"] = "E0AE7FBD5ECAE9E81275F7BD54646D9D2B8989D917BC8DAE5ECDEAB318041789", - ["JsonCompactColumnizer.dll"] = "7CC3AB761B646B61DBB9A5D2B10C303FCA3E2563FB013B98B433E9D01FA9E549", - ["Log4jXmlColumnizer.dll"] = "EF4F7FEEE0768B99927513E195A31287EB034E92FC12FCE6A08C17D4C178A4C6", - ["LogExpert.Core.dll"] = "A5BDC1F8EE28664CE135DEE750CCB5F8EE58F17243CCFBAEDCCDD55A1DFCEBC6", + ["CsvColumnizer.dll"] = "722A4BDCB8C37E359CB94BF23E6243A9A0D2B8597C57B26C13A313FFC55A08AC", + ["CsvColumnizer.dll (x86)"] = "722A4BDCB8C37E359CB94BF23E6243A9A0D2B8597C57B26C13A313FFC55A08AC", + ["DefaultPlugins.dll"] = "B410FF5A974AF3BC63EDE2A17A607CFB59AB9DB3B35DC8551F71ECC941144B6F", + ["FlashIconHighlighter.dll"] = "50A2BFE98957F927BE4AF8718CF83D7EA93B055067105706EF575023575AD525", + ["GlassfishColumnizer.dll"] = "9FEB23D586C8478B8658409CE8324B9F053AE42195582F6BF559E37DA4DA2409", + ["JsonColumnizer.dll"] = "2776219BCA395EA2013381C5182C1C9391D9465E6626E0FF0FCF14686A391C42", + ["JsonCompactColumnizer.dll"] = "0BD2A4254634F808A6C79AA04A3C3FB78AEEE4B48A62F5104C433FA657C37AFE", + ["Log4jXmlColumnizer.dll"] = "48CA1D0B743705EA7B09DC1D99B2D9262B82ADB0ACD1E823DCDA498387C2FD7C", + ["LogExpert.Core.dll"] = "103A69D52179DB534F7BA8357AF79B9F46D4C81E5D3C1C7FBF34295A16B72FAD", ["Microsoft.Extensions.DependencyInjection.Abstractions.dll"] = "67FA4325000DB017DC0C35829B416F024F042D24EFB868BCF17A895EE6500A93", ["Microsoft.Extensions.DependencyInjection.Abstractions.dll (x86)"] = "67FA4325000DB017DC0C35829B416F024F042D24EFB868BCF17A895EE6500A93", ["Microsoft.Extensions.Logging.Abstractions.dll"] = "BB853130F5AFAF335BE7858D661F8212EC653835100F5A4E3AA2C66A4D4F685D", ["Microsoft.Extensions.Logging.Abstractions.dll (x86)"] = "BB853130F5AFAF335BE7858D661F8212EC653835100F5A4E3AA2C66A4D4F685D", - ["RegexColumnizer.dll"] = "825F04C50018C57634824C425043FF720F1293E61B5CF3B0E5916BD53BAC757C", - ["SftpFileSystem.dll"] = "3E39DFA763EA1FF7B30DEA23C13F4AE449C30F983819E1657967DB4980A0C897", - ["SftpFileSystem.dll (x86)"] = "F8FBE4D54D6FC3B5D0CF5641D7F426351BE644E32512AAF287ADEC79C1A23A0A", - ["SftpFileSystem.Resources.dll"] = "A07D36296E27C09820BE8C4DE09E0BCE82129F0B0DD1A24940A89854AFED4F88", - ["SftpFileSystem.Resources.dll (x86)"] = "A07D36296E27C09820BE8C4DE09E0BCE82129F0B0DD1A24940A89854AFED4F88", + ["RegexColumnizer.dll"] = "F96A3CB255B20BC5E78A012AD982B90B5056ACC5262D093C7FF0C04C413C8A25", + ["SftpFileSystem.dll"] = "55DB42BA992586C9C0D5D47B9D80B6CB450BF6C250E9CF09998999B1F5037483", + ["SftpFileSystem.dll (x86)"] = "A964D6BC0ABF93A5574A43AF88C077E20BCE54D49E7F22769C385F0CED97A3D2", + ["SftpFileSystem.Resources.dll"] = "EFE491512DC7FBBC166C1274F7167259520A74B613445FC72A38D670C1CF3963", + ["SftpFileSystem.Resources.dll (x86)"] = "EFE491512DC7FBBC166C1274F7167259520A74B613445FC72A38D670C1CF3963", }; }