Skip to content

Commit 1ef497a

Browse files
authored
Merge pull request #492 from LogExperts/470-settings-deserialization-fails-if-filterparamscurrentcolumnizer-cant-be-deserialized
This pull request introduces several improvements and refactors across multiple columnizer implementations, focusing on interface consistency, code modernization, and minor bug fixes. The most significant changes are the addition of a new GetCustomName() method to the ILogLineColumnizer interface and its implementations, various code cleanups (including modern C# syntax), and updates to build requirements. Interface and API Consistency: Added GetCustomName() method to the ILogLineColumnizer interface and implemented it in all columnizer classes (AutoColumnizer, CsvColumnizer, GlassfishColumnizer, JsonColumnizer, and Log4jXmlColumnizer). This ensures a consistent way to retrieve user-assigned names for columnizers. [1] [2] [3] [4] [5] [6] Code Modernization and Cleanup: Replaced explicit array constructions and LINQ .ToArray() calls with collection expressions and spread operators for brevity and clarity in column assignments. [1] [2] [3] Used StringComparison.OrdinalIgnoreCase in string comparisons for more robust and culture-invariant checks. [1] [2] [3] Updated variable and constant naming to follow C# conventions (e.g., separatorChar to SEPARATOR_CHAR). [1] [2] Replaced repeated empty string assignments with string.Empty for clarity. Used CultureInfo.InvariantCulture in date formatting for consistent output. [1] [2] Removed unnecessary using directives for cleaner files. [1] [2] [3] [4] [5] Bug Fixes and Minor Improvements: Fixed a typo in the Glassfish columnizer name from "Classfish" to "Glassfish". Improved error handling by discarding unused return values with _ = in calls like MessageBox.Show and csv.Read(). [1] [2] [3] Simplified conditional logic and method bodies for readability and maintainability. [1] [2] Build and Documentation Updates: Updated build instructions and prerequisites to require .NET 10.0.100 SDK, target net10.0-windows, and recommend Visual Studio 2026+ for development. Columnizer-Specific Refactors: Refactored the handling of columnizer line splitting and timestamp parsing for improved reliability and maintainability in the CsvColumnizer, GlassfishColumnizer, and Log4jXmlColumnizer classes. [1] [2] [3] These changes collectively improve the maintainability, usability, and future extensibility of the codebase.
2 parents 73bdf59 + d7ecdfc commit 1ef497a

File tree

53 files changed

+3302
-1210
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+3302
-1210
lines changed

.github/copilot-instructions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
## Build Instructions
3737

3838
### Prerequisites
39-
**CRITICAL**: This project requires Windows development environment and .NET 9.0.301 SDK or compatible.
39+
**CRITICAL**: This project requires Windows development environment and .NET 10.0.100 SDK or compatible.
4040

4141
### Environment Setup
4242
1. **Install .NET SDK**: Project requires .NET 10.0.100 SDK (specified in `global.json`)

src/AutoColumnizer/AutoColumnizer.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
using System;
2-
31
using LogExpert;
42

53
namespace AutoColumnizer;
@@ -20,6 +18,11 @@ public string GetName ()
2018
return "Auto Columnizer";
2119
}
2220

21+
public string GetCustomName ()
22+
{
23+
return GetName();
24+
}
25+
2326
public string GetDescription ()
2427
{
2528
return "Automatically find the right columnizer for any file";

src/ColumnizerLib/ILogLineColumnizer.cs

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
using System;
2-
31
namespace LogExpert;
42

53
///<summary>
64
/// This interface defines a so-called 'Columnizer' for LogExpert.
75
/// A columnizer splits a single text line into well defined columns. These columns
86
/// are used in the data grid view of LogExpert.
9-
/// <br></br><br></br>
7+
/// <br></br><br></br>
108
/// Optionally a columnizer can parse the log line to determine the date/time of
119
/// the log line (assuming that all log lines have a timestamp). This is needed for
1210
/// some of the features of LogExpert (see user documentation for more information).
@@ -20,45 +18,50 @@ public interface ILogLineColumnizer
2018
/// <summary>
2119
/// Returns the name for the columnizer. This name is used for the columnizer selection dialog.
2220
/// </summary>
23-
string GetName();
21+
string GetName ();
22+
23+
/// <summary>
24+
/// Returns the name that is given by the user for this columnizer.
25+
/// </summary>
26+
string GetCustomName ();
2427

2528
/// <summary>
2629
/// Returns the description of the columnizer. This text is used in the columnizer selection dialog.
2730
/// </summary>
28-
string GetDescription();
31+
string GetDescription ();
2932

3033
/// <summary>
31-
/// Returns the number of columns the columnizer will split lines into.
34+
/// Returns the number of columns the columnizer will split lines into.
3235
/// </summary>
3336
/// <remarks>
34-
/// This value does not include the column for displaying the line number. The line number column
37+
/// This value does not include the column for displaying the line number. The line number column
3538
/// is added by LogExpert and is not handled by columnizers.
3639
/// </remarks>
37-
int GetColumnCount();
40+
int GetColumnCount ();
3841

3942
/// <summary>
4043
/// Returns the names of the columns. The returned names are used by LogExpert for the column headers in the data grid view.
41-
/// The names are expected in order from left to right.
44+
/// The names are expected in order from left to right.
4245
/// </summary>
43-
string[] GetColumnNames();
46+
string[] GetColumnNames ();
4447

4548
/// <summary>
46-
/// Given a single line of the logfile this function splits the line content into columns. The function returns
49+
/// Given a single line of the logfile this function splits the line content into columns. The function returns
4750
/// a string array containing the splitted content.
4851
/// </summary>
4952
/// <remarks>
5053
/// This function is called by LogExpert for every line that has to be drawn in the grid view. The faster your code
5154
/// handles the splitting, the faster LogExpert can draw the grid view content.<br></br>
5255
/// <br></br>
5356
/// Notes about timeshift handling:<br></br>
54-
/// If your columnizer implementation supports timeshift (see <see cref="IsTimeshiftImplemented">IsTimeshiftImplemented</see>)
57+
/// If your columnizer implementation supports timeshift (see <see cref="IsTimeshiftImplemented">IsTimeshiftImplemented</see>)
5558
/// you have to add the timestamp offset to the columns representing the timestamp (e.g. columns like 'date' and 'time').
56-
/// In practice this means you have to parse the date/time value of your log line (see <see cref="GetTimestamp">GetTimestamp</see>)
59+
/// In practice this means you have to parse the date/time value of your log line (see <see cref="GetTimestamp">GetTimestamp</see>)
5760
/// add the offset and convert the timestamp back to string value(s).
5861
/// </remarks>
5962
/// <param name="callback">Callback interface with functions which can be used by the columnizer</param>
6063
/// <param name="line">The line content to be splitted</param>
61-
IColumnizedLogLine SplitLine(ILogLineColumnizerCallback callback, ILogLine line);
64+
IColumnizedLogLine SplitLine (ILogLineColumnizerCallback callback, ILogLine line);
6265

6366
/// <summary>
6467
/// Returns true, if the columnizer supports timeshift handling.
@@ -67,23 +70,23 @@ public interface ILogLineColumnizer
6770
/// If you return true, you also have to implement the function SetTimeOffset(), GetTimeOffset() and GetTimestamp().
6871
/// You also must handle PushValue() for the column(s) that displays the timestamp.
6972
/// </remarks>
70-
bool IsTimeshiftImplemented();
73+
bool IsTimeshiftImplemented ();
7174

7275
/// <summary>
73-
/// Sets an offset to be used for displaying timestamp values. You have to implement this function, if
76+
/// Sets an offset to be used for displaying timestamp values. You have to implement this function, if
7477
/// your IsTimeshiftImplemented() function return true.
7578
/// </summary>
7679
/// <remarks>
77-
/// You have to store the given value in the Columnizer instance and add this offset to the timestamp column(s) returned by SplitLine()
80+
/// You have to store the given value in the Columnizer instance and add this offset to the timestamp column(s) returned by SplitLine()
7881
/// (e.g. in the date and time columns).
7982
/// </remarks>
8083
/// <param name="msecOffset">The timestamp offset in milliseconds.</param>
81-
void SetTimeOffset(int msecOffset);
84+
void SetTimeOffset (int msecOffset);
8285

8386
/// <summary>
8487
/// Returns the current stored timestamp offset (set by SetTimeOffset()).
8588
/// </summary>
86-
int GetTimeOffset();
89+
int GetTimeOffset ();
8790

8891
/// <summary>
8992
/// Returns the timestamp value of the given line as a .NET DateTime object. If there's no valid timestamp in the
@@ -99,7 +102,7 @@ public interface ILogLineColumnizer
99102
/// </remarks>
100103
/// <param name="callback">Callback interface with functions which can be used by the columnizer</param>
101104
/// <param name="line">The line content which timestamp has to be returned.</param>
102-
DateTime GetTimestamp(ILogLineColumnizerCallback callback, ILogLine line);
105+
DateTime GetTimestamp (ILogLineColumnizerCallback callback, ILogLine line);
103106

104107
/// <summary>
105108
/// This function is called if the user changes a value in a column (edit mode in the log view).
@@ -114,7 +117,7 @@ public interface ILogLineColumnizer
114117
/// <param name="column">The column number which value has changed.</param>
115118
/// <param name="value">The new value.</param>
116119
/// <param name="oldValue">The old value.</param>
117-
void PushValue(ILogLineColumnizerCallback callback, int column, string value, string oldValue);
120+
void PushValue (ILogLineColumnizerCallback callback, int column, string value, string oldValue);
118121

119122
#endregion
120123
}

src/CsvColumnizer/CsvColumnizer.cs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -61,19 +61,22 @@ public string PreProcessLine (string logLine, int lineNum, int realLineNum)
6161
return null; // hide from LogExpert
6262
}
6363

64-
if (_config.CommentChar != ' ' && logLine.StartsWith("" + _config.CommentChar))
65-
{
66-
return null;
67-
}
68-
69-
return logLine;
64+
return _config.CommentChar != ' ' &&
65+
logLine.StartsWith("" + _config.CommentChar, StringComparison.OrdinalIgnoreCase)
66+
? null
67+
: logLine;
7068
}
7169

7270
public string GetName ()
7371
{
7472
return "CSV Columnizer";
7573
}
7674

75+
public string GetCustomName ()
76+
{
77+
return GetName();
78+
}
79+
7780
public string GetDescription ()
7881
{
7982
return "Splits CSV files into columns.\r\n\r\nCredits:\r\nThis Columnizer uses the CsvHelper. https://github.com/JoshClose/CsvHelper. \r\n";
@@ -105,12 +108,9 @@ public string[] GetColumnNames ()
105108

106109
public IColumnizedLogLine SplitLine (ILogLineColumnizerCallback callback, ILogLine line)
107110
{
108-
if (_isValidCsv)
109-
{
110-
return SplitCsvLine(line);
111-
}
112-
113-
return CreateColumnizedLogLine(line);
111+
return _isValidCsv
112+
? SplitCsvLine(line)
113+
: CreateColumnizedLogLine(line);
114114
}
115115

116116
private static ColumnizedLogLine CreateColumnizedLogLine (ILogLine line)
@@ -119,6 +119,7 @@ private static ColumnizedLogLine CreateColumnizedLogLine (ILogLine line)
119119
{
120120
LogLine = line
121121
};
122+
122123
cLogLine.ColumnValues = [new Column { FullValue = line.FullLine, Parent = cLogLine }];
123124
return cLogLine;
124125
}
@@ -153,13 +154,15 @@ public void Selected (ILogLineColumnizerCallback callback)
153154
if (_isValidCsv) // see PreProcessLine()
154155
{
155156
_columnList.Clear();
156-
var line = _config.HasFieldNames ? _firstLine : callback.GetLogLine(0);
157+
var line = _config.HasFieldNames
158+
? _firstLine
159+
: callback.GetLogLine(0);
157160

158161
if (line != null)
159162
{
160163
using CsvReader csv = new(new StringReader(line.FullLine), _config.ReaderConfiguration);
161-
csv.Read();
162-
csv.ReadHeader();
164+
_ = csv.Read();
165+
_ = csv.ReadHeader();
163166

164167
var fieldCount = csv.Parser.Count;
165168

@@ -229,7 +232,7 @@ public void LoadConfig (string configDir)
229232
}
230233
catch (Exception e)
231234
{
232-
MessageBox.Show($"Error while deserializing config data: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
235+
_ = MessageBox.Show($"Error while deserializing config data: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
233236
_config = new CsvColumnizerConfig();
234237
_config.InitDefaults();
235238
}
@@ -252,16 +255,16 @@ public Priority GetPriority (string fileName, IEnumerable<ILogLine> samples)
252255

253256
#region Private Methods
254257

255-
private IColumnizedLogLine SplitCsvLine (ILogLine line)
258+
private ColumnizedLogLine SplitCsvLine (ILogLine line)
256259
{
257260
ColumnizedLogLine cLogLine = new()
258261
{
259262
LogLine = line
260263
};
261264

262265
using CsvReader csv = new(new StringReader(line.FullLine), _config.ReaderConfiguration);
263-
csv.Read();
264-
csv.ReadHeader();
266+
_ = csv.Read();
267+
_ = csv.ReadHeader();
265268

266269
//we only read line by line and not the whole file so it is always the header
267270
var records = csv.HeaderRecord;
@@ -275,7 +278,7 @@ private IColumnizedLogLine SplitCsvLine (ILogLine line)
275278
columns.Add(new Column { FullValue = record, Parent = cLogLine });
276279
}
277280

278-
cLogLine.ColumnValues = columns.Select(a => a as IColumn).ToArray();
281+
cLogLine.ColumnValues = [.. columns.Select(a => a as IColumn)];
279282
}
280283

281284
return cLogLine;

src/GlassfishColumnizer/GlassfishColumnizer.cs

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using System;
21
using System.Globalization;
3-
using System.Linq;
42

53
using ColumnizerLib;
64

@@ -15,7 +13,7 @@ internal class GlassfishColumnizer : ILogLineXmlColumnizer
1513
public const int COLUMN_COUNT = 2;
1614
private const string DATETIME_FORMAT = "yyyy-MM-ddTHH:mm:ss.fffzzzz";
1715
private const string DATETIME_FORMAT_OUT = "yyyy-MM-dd HH:mm:ss.fff";
18-
private const char separatorChar = '|';
16+
private const char SEPARATOR_CHAR = '|';
1917

2018
private static readonly XmlConfig xmlConfig = new();
2119

@@ -44,7 +42,7 @@ public ILogLine GetLineTextForClipboard (ILogLine logLine, ILogLineColumnizerCal
4442
{
4543
GlassFishLogLine line = new()
4644
{
47-
FullLine = logLine.FullLine.Replace(separatorChar, '|'),
45+
FullLine = logLine.FullLine.Replace(SEPARATOR_CHAR, '|'),
4846
LineNumber = logLine.LineNumber
4947
};
5048

@@ -53,7 +51,12 @@ public ILogLine GetLineTextForClipboard (ILogLine logLine, ILogLineColumnizerCal
5351

5452
public string GetName ()
5553
{
56-
return "Classfish";
54+
return "Glassfish";
55+
}
56+
57+
public string GetCustomName ()
58+
{
59+
return GetName();
5760
}
5861

5962
public string GetDescription ()
@@ -73,21 +76,23 @@ public string[] GetColumnNames ()
7376

7477
public IColumnizedLogLine SplitLine (ILogLineColumnizerCallback callback, ILogLine line)
7578
{
76-
ColumnizedLogLine cLogLine = new();
77-
cLogLine.LogLine = line;
79+
ColumnizedLogLine cLogLine = new()
80+
{
81+
LogLine = line
82+
};
7883

7984
var temp = line.FullLine;
8085

8186
var columns = Column.CreateColumns(COLUMN_COUNT, cLogLine);
82-
cLogLine.ColumnValues = columns.Select(a => a as IColumn).ToArray();
87+
cLogLine.ColumnValues = [.. columns.Select(a => a as IColumn)];
8388

8489
// delete '[#|' and '|#]'
85-
if (temp.StartsWith("[#|"))
90+
if (temp.StartsWith("[#|", StringComparison.OrdinalIgnoreCase))
8691
{
8792
temp = temp[3..];
8893
}
8994

90-
if (temp.EndsWith("|#]"))
95+
if (temp.EndsWith("|#]", StringComparison.OrdinalIgnoreCase))
9196
{
9297
temp = temp[..^3];
9398
}
@@ -108,7 +113,7 @@ public IColumnizedLogLine SplitLine (ILogLineColumnizerCallback callback, ILogLi
108113
columns[1].FullValue = temp;
109114
}
110115

111-
var newDate = dateTime.ToString(DATETIME_FORMAT_OUT);
116+
var newDate = dateTime.ToString(DATETIME_FORMAT_OUT, CultureInfo.InvariantCulture);
112117
columns[0].FullValue = newDate;
113118
}
114119
catch (Exception)
@@ -156,12 +161,12 @@ public DateTime GetTimestamp (ILogLineColumnizerCallback callback, ILogLine logL
156161
var temp = logLine.FullLine;
157162

158163
// delete '[#|' and '|#]'
159-
if (temp.StartsWith("[#|"))
164+
if (temp.StartsWith("[#|", StringComparison.OrdinalIgnoreCase))
160165
{
161166
temp = temp[3..];
162167
}
163168

164-
if (temp.EndsWith("|#]"))
169+
if (temp.EndsWith("|#]", StringComparison.OrdinalIgnoreCase))
165170
{
166171
temp = temp[..^3];
167172
}
@@ -171,8 +176,8 @@ public DateTime GetTimestamp (ILogLineColumnizerCallback callback, ILogLine logL
171176
return DateTime.MinValue;
172177
}
173178

174-
var endIndex = temp.IndexOf(separatorChar, 1);
175-
if (endIndex > 28 || endIndex < 0)
179+
var endIndex = temp.IndexOf(SEPARATOR_CHAR, 1);
180+
if (endIndex is > 28 or < 0)
176181
{
177182
return DateTime.MinValue;
178183
}
@@ -182,12 +187,9 @@ public DateTime GetTimestamp (ILogLineColumnizerCallback callback, ILogLine logL
182187
try
183188
{
184189
// convert glassfish timestamp into a readable format:
185-
if (DateTime.TryParseExact(value, DATETIME_FORMAT, cultureInfo, DateTimeStyles.None, out var timestamp))
186-
{
187-
return timestamp.AddMilliseconds(timeOffset);
188-
}
189-
190-
return DateTime.MinValue;
190+
return DateTime.TryParseExact(value, DATETIME_FORMAT, cultureInfo, DateTimeStyles.None, out var timestamp)
191+
? timestamp.AddMilliseconds(timeOffset)
192+
: DateTime.MinValue;
191193
}
192194
catch (Exception)
193195
{

0 commit comments

Comments
 (0)