Skip to content

Commit b2bd562

Browse files
authored
Merge pull request #697 from Pr0metheus2/fix/MultiFile-support-for-mid-filename-index-tags-(app.1.log)
Fix/MultiFile pattern (Issue #696)
2 parents b34f430 + ab3f3ee commit b2bd562

12 files changed

Lines changed: 117 additions & 40 deletions

File tree

‎src/LogExpert.Configuration/LegacyPreferencesMigrator.cs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,5 @@ private static void MigrateToV1 (Settings settings)
5555
}
5656
#pragma warning restore CS0618
5757
}
58+
5859
}

‎src/LogExpert.Core/Classes/Log/RolloverFilenameBuilder.cs‎

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ public class RolloverFilenameBuilder
2828
#region Fields
2929

3030
private string _condContent;
31-
private Group _condGroup;
3231
private string _currentFileName;
3332

3433
private Group _dateGroup;
@@ -41,6 +40,7 @@ public class RolloverFilenameBuilder
4140

4241
private bool _hideZeroIndex;
4342
private Group _indexGroup;
43+
private Group _indexPartGroup;
4444
private Regex _regex;
4545

4646
#endregion
@@ -89,7 +89,7 @@ public void SetFileName (string fileName)
8989
Index = _indexGroup.Value.Length > 0 ? int.Parse(_indexGroup.Value) : 0;
9090
}
9191

92-
_condGroup = match.Groups["cond"];
92+
_indexPartGroup = match.Groups["indexPart"];
9393
}
9494
}
9595

@@ -116,15 +116,15 @@ public string BuildFileName ()
116116

117117
if (_indexGroup != null && _indexGroup.Success)
118118
{
119-
fileName = fileName.Remove(_indexGroup.Index, _indexGroup.Length);
119+
fileName = fileName.Remove(_indexPartGroup.Index, _indexPartGroup.Length);
120120

121121
if (!_hideZeroIndex || Index > 0)
122122
{
123123
var format = "D" + _indexGroup.Length;
124-
fileName = fileName.Insert(_indexGroup.Index, Index.ToString(format));
124+
fileName = fileName.Insert(_indexPartGroup.Index, Index.ToString(format));
125125
if (_hideZeroIndex && _condContent != null)
126126
{
127-
fileName = fileName.Insert(_indexGroup.Index, _condContent);
127+
fileName = fileName.Insert(_indexPartGroup.Index, _condContent);
128128
}
129129
}
130130
}
@@ -141,14 +141,14 @@ public string BuildFileName ()
141141
private void ParseFormatString (string formatString)
142142
{
143143
var fmt = EscapeNonvarRegions(formatString);
144-
var datePos = formatString.IndexOf("$D(", StringComparison.Ordinal);
144+
var datePos = fmt.IndexOf("$D(", StringComparison.Ordinal);
145145

146146
if (datePos != -1)
147147
{
148-
var endPos = formatString.IndexOf(')', datePos);
148+
var endPos = fmt.IndexOf(')', datePos);
149149
if (endPos != -1)
150150
{
151-
_dateTimeFormat = formatString.Substring(datePos + 3, endPos - datePos - 3)
151+
_dateTimeFormat = fmt.Substring(datePos + 3, endPos - datePos - 3)
152152
.ToUpperInvariant()
153153
.Replace('D', 'd')
154154
.Replace('Y', 'y');
@@ -176,12 +176,17 @@ private void ParseFormatString (string formatString)
176176
}
177177
}
178178

179-
fmt = fmt.Replace("*", ".*", StringComparison.Ordinal);
179+
fmt = fmt.Replace("*", ".*?", StringComparison.Ordinal);
180180
_hideZeroIndex = fmt.Contains("$J", StringComparison.Ordinal);
181-
fmt = fmt.Replace("$I", "(?'index'[\\d]+)", StringComparison.Ordinal);
182-
fmt = fmt.Replace("$J", "(?'index'[\\d]*)", StringComparison.Ordinal);
183-
184-
_regex = new Regex(fmt);
181+
const string indexPattern = "(?'indexPart'(?'index'[\\d]+))";
182+
const string hiddenZeroIndexPattern = "(?'indexPart'(?'index'[\\d]*))";
183+
var conditionalIndexPattern = _condContent != null
184+
? $"(?'indexPart'(?:{Regex.Escape(_condContent)}(?'index'[\\d]+)|(?'index')))"
185+
: hiddenZeroIndexPattern;
186+
fmt = fmt.Replace("$I", indexPattern, StringComparison.Ordinal);
187+
fmt = fmt.Replace("$J", conditionalIndexPattern, StringComparison.Ordinal);
188+
189+
_regex = new Regex(fmt + @"\z");
185190
}
186191

187192
private string EscapeNonvarRegions (string formatString)
@@ -199,17 +204,15 @@ private string EscapeNonvarRegions (string formatString)
199204
case 0: // looking for $
200205
if (fmt[i] == '$')
201206
{
202-
_ = result.Append(Regex.Escape(segment.ToString()));
203-
segment = new StringBuilder();
207+
AppendEscapedSegment(result, segment);
204208
state = 1;
205209
}
206210

207211
_ = segment.Append(fmt[i]);
208212
break;
209213
case 1: // the char behind $
210214
_ = segment.Append(fmt[i]);
211-
_ = result.Append(segment);
212-
segment = new StringBuilder();
215+
AppendSegment(result, segment);
213216
state = 2;
214217
break;
215218
case 2: // checking if ( or other char
@@ -229,18 +232,30 @@ private string EscapeNonvarRegions (string formatString)
229232
_ = segment.Append(fmt[i]);
230233
if (fmt[i] == ')')
231234
{
232-
_ = result.Append(segment);
233-
segment = new StringBuilder();
235+
AppendSegment(result, segment);
234236
state = 0;
235237
}
236238

237239
break;
238240
}
239241
}
240242

243+
AppendEscapedSegment(result, segment);
241244
fmt = result.ToString().Replace('\xFFFD', '*');
242245
return fmt;
243246
}
244247

248+
private static void AppendEscapedSegment (StringBuilder result, StringBuilder segment)
249+
{
250+
_ = result.Append(Regex.Escape(segment.ToString()));
251+
_ = segment.Clear();
252+
}
253+
254+
private static void AppendSegment (StringBuilder result, StringBuilder segment)
255+
{
256+
_ = result.Append(segment);
257+
_ = segment.Clear();
258+
}
259+
245260
#endregion
246-
}
261+
}

‎src/LogExpert.Resources/Resources.de.resx‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1680,12 +1680,16 @@ Ein ausgewähltes Tool erscheint in der Iconbar. Alle anderen verfügbaren Tools
16801680
<value>Muster syntax:
16811681

16821682
* = alle Zeichen (wildcard)
1683-
$D(&amp;lt;date&amp;gt;) = Datumsmuster
1683+
$D(&lt;date&gt;) = Datumsmuster
16841684
$I = Dateiindexnummer
1685-
$J = Dateiindexnummer, versteckt wenn 09
1686-
$J(&amp;lt;prefix&amp;gt;) = Wie $J, jedoch wird ein &amp;lt;prefix&amp;gt; hinzugefügt when es nicht 0 ist
1685+
$J = Dateiindexnummer, versteckt wenn null
1686+
$J(&lt;prefix&gt;) = Wie $J, jedoch wird ein &lt;prefix&gt; hinzugefügt wenn es nicht 0 ist
16871687

1688-
&amp;lt;date&amp;gt;:
1688+
Beispiele:
1689+
*$J(.) → app.log, app.log.1, app.log.2
1690+
*$J(.).log → app.log, app.1.log, app.2.log
1691+
1692+
&lt;date&gt;:
16891693
DD = Tag
16901694
MM = Monat
16911695
YY[YY] = Jahr

‎src/LogExpert.Resources/Resources.resx‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1743,12 +1743,16 @@ Checked tools will appear in the icon bar. All other tools are available in the
17431743
<value>Pattern syntax:
17441744

17451745
* = any characters (wildcard)
1746-
$D(&amp;lt;date&amp;gt;) = Date pattern
1746+
$D(&lt;date&gt;) = Date pattern
17471747
$I = File index number
17481748
$J = File index number, hidden when zero
1749-
$J(&amp;lt;prefix&amp;gt;) = Like $J, but adding &amp;lt;prefix&amp;gt; when non-zero
1749+
$J(&lt;prefix&gt;) = Like $J, but adding &lt;prefix&gt; when non-zero
17501750

1751-
&amp;lt;date&amp;gt;:
1751+
Examples:
1752+
*$J(.) → app.log, app.log.1, app.log.2
1753+
*$J(.).log → app.log, app.1.log, app.2.log
1754+
1755+
&lt;date&gt;:
17521756
DD = day
17531757
MM = month
17541758
YY[YY] = year

‎src/LogExpert.Resources/Resources.zh-CN.resx‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1554,6 +1554,10 @@ $I = 文件索引编号
15541554
$J = 文件索引编号,为零时隐藏
15551555
$J(&lt;前缀&gt;) = 类似 $J,但在非零时添加 &lt;前缀&gt;
15561556

1557+
示例:
1558+
*$J(.) → app.log, app.log.1, app.log.2
1559+
*$J(.).log → app.log, app.1.log, app.2.log
1560+
15571561
&lt;日期&gt;:
15581562
DD = 日
15591563
MM = 月

‎src/LogExpert.Tests/LogExpert.Tests.csproj‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@
111111
<Content Include="TestData\app.log.1">
112112
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
113113
</Content>
114+
<Content Include="TestData\app.1.log">
115+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
116+
</Content>
117+
<Content Include="TestData\app.2.log">
118+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
119+
</Content>
114120
<None Update="TestData\organizations-1000.csv">
115121
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
116122
</None>

‎src/LogExpert.Tests/RollingNameTest.cs‎

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ public void TestFilename1(string expectedResult, string formatString)
3232
[TestCase("engine.log", "engine1.log","engine$J.log")]
3333
[TestCase("engine1.log", "engine2.log","engine$J.log")]
3434
[TestCase("engine.log", "engine.log.1","*$J(.)")]
35+
[TestCase("engine.log", "engine.1.log", "*$J(.).log")]
36+
[TestCase("engine.log.1", "engine.log.2", "*$J(.)")]
37+
[TestCase("engine.1.log", "engine.2.log", "*$J(.).log")]
38+
[TestCase("engine1.log", "engine2.log", "*$I.log")]
39+
[TestCase("engine_2010-06-12.1.log", "engine_2010-06-12.2.log", "*$D(yyyy-MM-dd)$J(.).log")]
3540
[TestCase("engine_2010-06-12.log", "engine_2010-06-12.log.1", "*$D(yyyy-MM-dd).log$J(.)")]
3641
public void TestFilenameAnd1(string fileName, string expectedResult, string formatString)
3742
{
@@ -45,6 +50,7 @@ public void TestFilenameAnd1(string fileName, string expectedResult, string form
4550
[Test]
4651
[TestCase("engine.log", "engine.log.2","*$J(.)")]
4752
[TestCase("engine.log", "engine.log.2","*.log$J(.)")]
53+
[TestCase("engine.log", "engine.2.log", "*$J(.).log")]
4854
public void TestFilenameAnd2(string fileName, string expectedResult, string formatString)
4955
{
5056
RolloverFilenameBuilder fnb = new(formatString);
@@ -54,6 +60,27 @@ public void TestFilenameAnd2(string fileName, string expectedResult, string form
5460
Assert.That(name, Is.EqualTo(expectedResult));
5561
}
5662

63+
[Test]
64+
public void TestFilenameDateAfterRegexMetacharacter ()
65+
{
66+
RolloverFilenameBuilder fnb = new("app.$D(yyyy-MM-dd).log");
67+
fnb.SetFileName("app.2010-06-12.log");
68+
69+
fnb.IncrementDate();
70+
71+
Assert.That(fnb.BuildFileName(), Is.EqualTo("app.2010-06-13.log"));
72+
}
73+
74+
[Test]
75+
public void BuildFileName_FullPathWithNonWildcardMask_IncrementsIndex ()
76+
{
77+
RolloverFilenameBuilder fnb = new("engine$J.log");
78+
fnb.SetFileName(@"C:\logs\engine1.log");
79+
80+
fnb.Index += 1;
81+
82+
Assert.That(fnb.BuildFileName(), Is.EqualTo(@"C:\logs\engine2.log"));
83+
}
5784

5885
[Test]
5986
[TestCase("engine1.log", "engine.log","engine$J.log")]
@@ -65,4 +92,4 @@ public void TestFilenameMinus1(string fileName, string expectedResult, string fo
6592
var name = fnb.BuildFileName();
6693
Assert.That(name, Is.EqualTo("engine.log"));
6794
}
68-
}
95+
}

‎src/LogExpert.Tests/StreamReaderTests/LogfileReaderMultiFileFlagTests.cs‎

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,24 @@ public void SingleFileCtor_MultiFileTrue_ExpandsRollover ()
6868
});
6969
}
7070

71+
[Test]
72+
public void SingleFileCtor_MultiFileTrue_LoadsIndexBeforeExtension ()
73+
{
74+
var options = new MultiFileOptions { FormatPattern = "*$J(.).log" };
75+
File.Copy(Path.Combine(_testDataDirectory, "app.1.log"), Path.Combine(_testDirectory, "app.1.log"));
76+
File.Copy(Path.Combine(_testDataDirectory, "app.2.log"), Path.Combine(_testDirectory, "app.2.log"));
77+
using var reader = CreateSingleFileReader(multiFile: true, options);
78+
79+
reader.ReadFiles();
80+
81+
Assert.Multiple(() =>
82+
{
83+
Assert.That(reader.IsMultiFile, Is.True);
84+
Assert.That(reader.GetLogFileInfoList().Select(file => Path.GetFileName(file.FullName)),
85+
Is.EqualTo(new[] { "app.2.log", "app.1.log", "app.log" }));
86+
});
87+
}
88+
7189
[Test]
7290
public void MultiFileCtor_AlwaysMultiFile ()
7391
{
@@ -91,15 +109,15 @@ public void MultiFileCtor_AlwaysMultiFile ()
91109
});
92110
}
93111

94-
private LogfileReader CreateSingleFileReader (bool multiFile)
112+
private LogfileReader CreateSingleFileReader (bool multiFile, MultiFileOptions? options = null)
95113
{
96114
return new LogfileReader(
97115
_logFile,
98116
new EncodingOptions { Encoding = Encoding.UTF8 },
99117
multiFile,
100118
bufferCount: 40,
101119
linesPerBuffer: 50,
102-
new MultiFileOptions(),
120+
options ?? new MultiFileOptions(),
103121
ReaderType.System,
104122
PluginRegistry.PluginRegistry.Instance,
105123
maximumLineLength: 500,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
app.1.log
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
app.2.log

0 commit comments

Comments
 (0)