我正在尝试使日志查看器显示来自不同来源的事件,但是按时间戳排序。我有一个感觉我可以使用C#Linq这个但是怎么样?
示例:我有一个事件列表,从文件读取到按日期时间戳排序的strig列表。
另一个事件来源是数据库插入,我使用Linq来提取与第一个列表相同的时间段。数据库也有时间戳。
我想要的是列出所有列出的实时事件列表。数据库插入可能会导致在一秒钟后记录在磁盘文件中的异常。
我想我正在寻找一种方法来加入和排序这些列表,只共享一个共同字段的时间戳,最后得到一个我可以使用foreach的集合,即使每个元素可能是不同的类型。
任何想法?
马丁
答案 0 :(得分:1)
我认为下面的代码应该达到你想要的效果。
基本上你只需要创建一个对象列表然后添加你的db&列表文件记录到该列表。完成后,您可以编写一个代理来处理排序
List<Db> db_inserts = new List<Db>();
// populate list of db events here
List<Fi> files = new List<Fi>();
// populate list of file events here
List<object> all = new List<object>();
all.AddRange(db_inserts.Cast<object>());
all.AddRange(files.Cast<object>());
// sort the list by time
all.Sort(delegate(object a, object b)
{
DateTime aTime = DateTime.MinValue;
DateTime bTime = DateTime.MinValue;
if (a is Db)
aTime = ((Db)a).time;
else if (a is Fi)
aTime = ((Fi)a).time;
if (b is Db)
bTime = ((Db)b).time;
else if (b is Fi)
bTime = ((Fi)b).time;
return aTime.CompareTo(bTime);
});
编辑:上面的代码可以使用下面的代码进行改进(假设LogItem是一个像@Mark Byers回复的容器类:
List<LogItem> all = new List<LogItem>();
all.AddRange(db_inserts.Select(x => new LogItem { time = x.time, msg = x.name, source=x}));
all.AddRange(files.Select(x => new LogItem{time = x.time, msg = x.name, source = x}));
var query = all.OrderBy(x => x.time);
答案 1 :(得分:1)
您可以使用Linq将两个数据源转换为相同的类型,然后将它们组合并对它们进行排序。这里我有一些来自伪装数据库表T_Log的对象,它有一个Timestamp字段和一些其他字段,另一个来源是伪文件中的一些字符串,其中每个字符串在行的开头包含一个时间戳。我将它们转换为自定义类CommonLog
,然后使用它进行排序。 CommonLog包含对原始对象的引用,因此如果我需要更详细的信息,我可以投射并获取该信息。
更轻量级的实现可以转换为已存在的类,例如KeyValuePair<DateTime, object>
。
以下是代码:
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
// Fake database class.
class T_Log
{
public DateTime Timestamp { get; set; }
public string Info { get; set; }
public int Priority { get; set; }
}
static void Main(string[] args)
{
// Create some events in the fake database.
List<T_Log> dbLogs = new List<T_Log> {
new T_Log { Timestamp = new DateTime(2009, 2, 5), Info = "db: foo", Priority = 1 },
new T_Log { Timestamp = new DateTime(2009, 2, 9), Info = "db: bar", Priority = 2 }
};
// Create some lines in a fake file.
List<string> fileLogs = new List<string> {
"2009-02-06: File foo",
"2009-02-10: File bar"
};
var logFromDb =
dbLogs.Select(x => new CommonLog(
x.Timestamp,
string.Format("{1} [Priority={2}]",
x.Timestamp,
x.Info,
x.Priority),
x));
var logFromFile =
fileLogs.Select(x => new CommonLog(
DateTime.Parse(x.Substring(0, x.IndexOf(':'))),
x.Substring(x.IndexOf(':') + 2),
x
));
var combinedLog = logFromDb.Concat(logFromFile).OrderBy(x => x.Timestamp);
foreach (var logEntry in combinedLog)
Console.WriteLine("{0}: {1}", logEntry.Timestamp, logEntry.Log);
}
}
// This class is used to store logs from any source.
class CommonLog
{
public CommonLog(DateTime timestamp,
string log,
object original)
{
this.Timestamp = timestamp;
this.Log = log;
this.Original = original;
}
public DateTime Timestamp { get; private set; }
public string Log { get; private set; }
public object Original { get; private set; }
}
输出:
05-02-2009 00:00:00: db: foo [Priority=0]
06-02-2009 00:00:00: file: baz
09-02-2009 00:00:00: db: bar [Priority=0]
10-02-2009 00:00:00: file: quux
更新:Martin在对此帖的评论中回复了以下内容,但由于评论中缺少格式,因此难以阅读。这是格式化:
var ld = rs.Select(x => new KeyValuePair<DateTime, object>(DateTime.Parse(x[0]), x))
.Concat(ta.Select(y => new KeyValuePair<DateTime, object>(y.Tidspunkt, y)))
.OrderBy(d => d.Key);
答案 2 :(得分:1)
连接日志源,然后对结果进行排序。假设每个日志源都是IEnumerable<LogEntry>
:
var logSources = new []
{
GetFileLogs(),
GetDbLogs()
// whatever other sources you need...
};
var entries = Enumerable.Empty<LogEntry>();
foreach (var source in logSources)
{
entries = entries.Concat(source);
}
entries = entries.OrderBy(e => e.Timestamp);