使用C#字典解析日志文件
本文关键字:日志 文件 字典 使用 | 更新日期: 2023-09-27 18:29:21
我正在尝试解析一个相当长的日志文件,并创建一个更好、更易于管理的问题列表。
我能够逐行读取和解析单个日志,但我需要做的是只显示唯一的条目,因为有些错误发生的频率比其他错误高,并且总是用相同的文本记录。
我要做的是创建一个Dictionary对象来保存每个唯一的条目,当我处理日志文件时,搜索Dictionary物体,看看是否已经有了相同的值。
这是我的一个粗略的代码示例(一项正在进行的工作,我希望我的语法都正确),但它不起作用。出于某种原因,此脚本从未看到任何不同的条目(若语句从未通过):
string[] rowdta = new string[4];
Dictionary<string[], int> dict = new Dictionary<string[], int>();
int ctr = -1;
if (linectr == 1)
{
ctr++;
dict.Add(rowdta, ctr);
}
else
{
foreach (KeyValuePair<string[], int> pair in dict)
{
if ((pair.Key[1] != rowdta[1]) || (pair.Key[2] != rowdta[2])| (pair.Key[3] != rowdta[3]))
{
ctr++;
dict.Add(rowdta, ctr);
}
}
}
一些示例数据:一线
rowdta[0]="ErrorType";
rowdta[1]="Undefined offset: 0";
rowdta[2]="/url/routesDisplay2.svc.php";
rowdta[3]="Line Number 5";
二线
rowdta[0]="ErrorType";
rowdta[1]="Undefined offset: 0";
rowdta[2]="/url/routesDisplay2.svc.php";
rowdta[3]="Line Number 5";
第三行
rowdta[0]="ErrorType";
rowdta[1]="Undefined variable: fvmsg";
rowdta[2]="/url/processes.svc.php";
rowdta[3]="Line Number 787";
因此,有了这个,字典将有两个项目,第一行和第三行。
我也尝试过以下内容,nalso在日志文件文本中没有发现任何变化。
if (!dict.ContainsKey(rowdta)) {}
有人能帮我把这个语法弄对吗?我只是C#的一个新手,但这应该相对简单。和往常一样,我认为这应该是足够的信息来开始对话。如果你想要/需要更多的细节,请告诉我。
为实现IEquatable的字符串创建一个包装器。
public class LogFileEntry :IEquatable<LogFileEntry>
{
private readonly string[] _rows;
public LogFileEntry(string[] rows)
{
_rows = rows;
}
public override int GetHashCode()
{
return
_rows[0].GetHashCode() << 3 |
_rows[2].GetHashCode() << 2 |
_rows[1].GetHashCode() << 1 |
_rows[0].GetHashCode();
}
#region Implementation of IEquatable<LogFileEntry>
public override bool Equals(Object obj)
{
if (obj == null)
return base.Equals(obj);
return Equals(obj as LogFileEntry);
}
public bool Equals(LogFileEntry other)
{
if(other == null)
return false;
return _rows.SequenceEqual(other._rows);
}
#endregion
}
然后在你的字典里用这个:
var d = new Dictionary<LogFileEntry, int>();
var entry = new LogFileEntry(rows);
if( d.ContainsKey(entry) )
{
d[entry] ++;
}
else
{
d[entry] = 1;
}
或者创建一个类似于@dasblinkenlight提出的自定义比较器,并使用以下
public class LogFileEntry
{
}
public class LogFileEntryComparer : IEqualityComparer<LogFileEntry>{ ... }
var d = new Dictionary<LogFileEntry, int>(new LogFileEntryComparer());
var entry = new LogFileEntry(rows);
if( d.ContainsKey(entry) )
{
d[entry] ++;
}
else
{
d[entry] = 1;
}
您看到问题的原因是,如果不提供自定义IEqualityComparer<string[]>
或编写包装,字符串数组就不能用作字典中的键。
EDIT以下是自定义比较器的快速而肮脏的实现:
private class ArrayEq<T> : IEqualityComparer<T[]> {
public bool Equals(T[] x, T[] y) {
return x.SequenceEqual(y);
}
public int GetHashCode(T[] obj) {
return obj.Sum(o => o.GetHashCode());
}
}
以下是如何使用它:
var dd = new Dictionary<string[], int>(new ArrayEq<string>());
dd[new[] { "a", "b" }] = 0;
dd[new[] { "a", "b" }]++;
dd[new[] { "a", "b" }]++;
Console.WriteLine(dd[new[] { "a", "b" }]);
问题是数组相等就是引用相等。换句话说,它不取决于存储在数组中的值,它只取决于数组的标识。
的一些解决方案
- 使用
Tuple
保存行数据 - 使用匿名类型保存行数据
- 创建一个自定义类型来保存行数据,如果是类,则重写Equals和GetHashCode
- 创建IEqualityComparer的自定义实现,根据数组的值对其进行比较,并在创建时将其传递给字典