Skip to content

Commit 5299637

Browse files
authored
Changed custom pattern handling to not silently ignore errors and other minor improvements (#53)
* Changed custom pattern handling to not silently ignore errors, but at least store them in a violations list * Updated #53 to include the recommended code changes by the repository owner
1 parent 8130f2f commit 5299637

File tree

5 files changed

+72
-43
lines changed

5 files changed

+72
-43
lines changed

src/Grok.Net.Tests/Grok.Net.Tests.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
<None Update="Resources\grok-custom-patterns">
2828
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
2929
</None>
30+
<None Update="Resources\grok-custom-patterns-invalid">
31+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
32+
</None>
3033
<None Update="Resources\example-log-file">
3134
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
3235
</None>
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
ZIPCODE [1-9]{1}[0-9]{2}\s{0,1}[0-9]{3}
22
FLOAT [+-]?([0-9]*[.,])?[0-9]+
3-
WRONGPATTERN1 \\\\\
4-
WRONGPATTERN2 \\\\\
53
WRONGFLOAT .*
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
WRONGPATTERN1 \\\\\
2+
WRONGPATTERN2 \\\\\

src/Grok.Net.Tests/UnitTests.cs

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.IO;
34
using GrokNet;
45
using Xunit;
@@ -9,7 +10,8 @@ public class UnitTests
910
{
1011
private static Stream ReadCustomFile() =>
1112
File.OpenRead($"Resources{Path.DirectorySeparatorChar}grok-custom-patterns");
12-
13+
private static Stream ReadCustomFileWithInvalidPatterns() =>
14+
File.OpenRead($"Resources{Path.DirectorySeparatorChar}grok-custom-patterns-invalid");
1315
[Fact]
1416
public void Parse_Empty_Logs_Not_Throws()
1517
{
@@ -127,7 +129,7 @@ public void Parse_IPv4_Pattern()
127129
[InlineData("2001:db8:85a3:0:0:8a2e:370:7334")]
128130
[InlineData("2001:db8:85a3::8a2e:370:7334")]
129131
[InlineData("::1")] // Loopback
130-
[InlineData("::")] // Default route
132+
[InlineData("::")] // Default route
131133
public void Parse_IPv6_Pattern(string ipAddress)
132134
{
133135
// Arrange
@@ -196,29 +198,34 @@ public void Load_Custom_Patterns(string zipcode)
196198
Assert.Equal(email, grokResult[1].Value);
197199
}
198200

199-
[Fact]
200-
public void Load_Wrong_Custom_Patterns()
201+
[Theory]
202+
[InlineData("122001")]
203+
[InlineData("122 001")]
204+
[InlineData("235 012")]
205+
public void Load_Custom_Patterns_From_IDictionary(string zipcode)
201206
{
202207
// Arrange
203-
const string client = "192.168.1.1";
204-
const string duration = "1";
208+
var customPatterns = new Dictionary<string, string>
209+
{
210+
{ "ZIPCODE", "[1-9]{1}[0-9]{2}\\s{0,1}[0-9]{3}" },
211+
{ "FLOAT", "[+-]?([0-9]*[.,]}?[0-9]+)" }
212+
};
213+
const string email = "[email protected]";
205214

206-
var sut = new Grok("%{WRONGPATTERN1:duration}:%{WRONGPATTERN2:client}", ReadCustomFile());
215+
var sut = new Grok("%{ZIPCODE:zipcode}:%{EMAILADDRESS:email}", customPatterns);
207216

208-
try
209-
{
210-
// Act
211-
GrokResult grokResult = sut.Parse($"{duration}:{client}");
212-
213-
// Assert (checks if regex is invalid)
214-
Assert.Equal("", grokResult[0].Value);
215-
Assert.Equal("", grokResult[1].Value);
216-
}
217-
catch
218-
{
219-
// Assert (checks if pattern is invalid)
220-
Assert.Throws<FormatException>(() => sut.Parse($"{duration}:{client}"));
221-
}
217+
// Act
218+
GrokResult grokResult = sut.Parse($"{zipcode}:{email}");
219+
220+
// Assert
221+
Assert.Equal(zipcode, grokResult[0].Value);
222+
Assert.Equal(email, grokResult[1].Value);
223+
}
224+
225+
[Fact]
226+
public void Load_Invalid_Custom_Patterns()
227+
{
228+
Assert.Throws<FormatException>(() => new Grok("%{WRONGPATTERN1:duration}:%{WRONGPATTERN2:client}", ReadCustomFileWithInvalidPatterns()));
222229
}
223230

224231
[Fact]
@@ -247,7 +254,7 @@ public void Parse_Pattern_With_Type_Should_Parse_To_Specified_Type()
247254
Assert.Equal(floatValue, grokResult[2].Value);
248255
Assert.IsType<double>(grokResult[2].Value); // Float converts to double actually
249256
}
250-
257+
251258
[Theory]
252259
[InlineData("INT", "2147483648", "int")]
253260
[InlineData("DATESTAMP", "11-31-2021 02:08:58", "datetime")]
@@ -264,5 +271,6 @@ public void Parse_With_Type_Parse_Exception_Should_Ignore_Type(string regex, str
264271
Assert.Equal(nameof(parse), grokResult[0].Key);
265272
Assert.Equal(parse, grokResult[0].Value);
266273
}
274+
267275
}
268-
}
276+
}

src/Grok.Net/Grok.cs

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@ public class Grok
1919
private static readonly Regex _grokRegex = new Regex("%{(\\w+):(\\w+)(?::\\w+)?}", RegexOptions.Compiled);
2020
private static readonly Regex _grokRegexWithType = new Regex("%{(\\w+):(\\w+):(\\w+)?}", RegexOptions.Compiled);
2121
private static readonly Regex _grokWithoutName = new Regex("%{(\\w+)}", RegexOptions.Compiled);
22-
22+
2323
public Grok(string grokPattern)
2424
{
2525
_grokPattern = grokPattern;
2626
_patterns = new Dictionary<string, string>();
2727
_typeMaps = new Dictionary<string, string>();
28+
2829
LoadPatterns();
2930
}
3031

@@ -33,6 +34,29 @@ public Grok(string grokPattern, Stream customPatterns)
3334
{
3435
LoadCustomPatterns(customPatterns);
3536
}
37+
38+
public Grok(string grokPattern, IDictionary<string,string> customPatterns)
39+
:this(grokPattern)
40+
{
41+
AddPatterns(customPatterns);
42+
}
43+
44+
private void AddPatterns(IDictionary<string,string> customPatterns)
45+
{
46+
foreach (var pattern in customPatterns)
47+
{
48+
AddPatternIfNotExists(pattern.Key, pattern.Value);
49+
}
50+
}
51+
52+
private void AddPatternIfNotExists(string key, string value)
53+
{
54+
if (!_patterns.ContainsKey(key))
55+
{
56+
EnsurePatternIsValid(value);
57+
_patterns.Add(key, value);
58+
}
59+
}
3660

3761
public GrokResult Parse(string text)
3862
{
@@ -149,26 +173,25 @@ private void ProcessPatternLine(string line)
149173
string[] strArray = line.Split(new[] { ' ' }, 2);
150174
if (strArray.Length != 2)
151175
{
152-
throw new FormatException("Custom pattern was not in a correct form");
176+
throw new FormatException("Pattern line was not in a correct form (two strings split by space)");
153177
}
154178

155-
if (strArray[0].Equals("#", StringComparison.OrdinalIgnoreCase))
179+
if (strArray[0].StartsWith("#"))
156180
{
157181
return;
158182
}
183+
AddPatternIfNotExists(strArray[0], strArray[1]);
184+
}
185+
186+
private void EnsurePatternIsValid(string pattern)
187+
{
159188
try
160189
{
161-
Regex.Match("", strArray[1]);
190+
_ = Regex.Match("", pattern);
162191
}
163-
catch
192+
catch(Exception e)
164193
{
165-
return;
166-
}
167-
168-
// check before adding to avoid an exception in case the same pattern is present in the custom patterns file.
169-
if (!_patterns.ContainsKey(strArray[0]))
170-
{
171-
_patterns.Add(strArray[0], strArray[1]);
194+
throw new FormatException($"Invalid regular expression {pattern}", e);
172195
}
173196
}
174197

@@ -177,12 +200,7 @@ private string ReplaceWithName(Match match)
177200
Group group1 = match.Groups[2];
178201
Group group2 = match.Groups[1];
179202

180-
if (_patterns.TryGetValue(group2.Value, out var str))
181-
{
182-
return $"(?<{group1}>{str})";
183-
}
184-
185-
return $"(?<{group1}>)";
203+
return _patterns.TryGetValue(group2.Value, out var str) ? $"(?<{group1}>{str})" : $"(?<{group1}>)";
186204
}
187205

188206
private string ReplaceWithoutName(Match match)

0 commit comments

Comments
 (0)