Source/Tx.Windows/IIS/W3CEnumerable.cs (115 lines of code) (raw):
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reactive;
using System.Reflection;
namespace Tx.Windows
{
public static class W3CEnumerable
{
public static IEnumerable<W3CEvent> FromFiles(params string[] logfiles)
{
if (logfiles.Length == 1)
return FromFile(logfiles[0]);
IEnumerable<IEnumerator<W3CEvent>> inputs = from file in logfiles select FromFile(file).GetEnumerator();
return new PullMergeSort<W3CEvent>(e => e.dateTime, inputs);
}
public static IEnumerable<W3CEvent> FromFile(string file)
{
using (var reader = File.OpenText(file))
{
IEnumerable<W3CEvent> enumerable = FromStream(reader);
for (;;)
{
foreach (var e in enumerable)
yield return e;
break;
}
}
}
public static IEnumerable<W3CEvent> FromStream(StreamReader reader)
{
Expression<Func<string[], W3CEvent>> transformExpression;
Func<string[], W3CEvent> transform = null;
for (;;)
{
string line = reader.ReadLine();
if (line == null)
yield break;
if (line.StartsWith("#Fields:"))
{
transformExpression = GetTransformExpression(line);
transform = transformExpression.Compile();
continue;
}
if (line.StartsWith("#"))
continue;
string[] tokens = line.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < tokens.Length; i++)
if (tokens[i] == "-")
tokens[i] = null;
W3CEvent e = transform(tokens);
yield return e;
}
}
static Expression<Func<string[], W3CEvent>> GetTransformExpression(string fieldsHeader)
{
Expression<Func<string[], W3CEvent>> template = (tok) => new W3CEvent { c_ip = tok[8] };
LambdaExpression ex = template;
var mi = (MemberInitExpression)ex.Body;
var bindings = new List<MemberBinding>();
ParameterExpression args = ex.Parameters[0];
string[] tokens = fieldsHeader.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
int dateIndex = 0;
int timeIndex = 0;
for (int i=1; i<tokens.Length; i++)
{
string property = MakeIdentifier(tokens[i]);
if (property == "date")
{
dateIndex = i-1;
continue;
}
if (property == "time")
{
timeIndex = i-1;
continue;
}
PropertyInfo targetProperty = typeof(W3CEvent).GetProperty(property);
if (targetProperty != null)
{
MemberAssignment b = Expression.Bind(
targetProperty,
Expression.ArrayIndex(args, Expression.Constant(i - 1)));
bindings.Add(b);
}
}
MemberBinding bdt = Expression.Bind(
typeof(W3CEvent).GetProperty("dateTime"),
Expression.Call(
null,
typeof(W3CEnumerable).GetMethod("ParseDateTime", BindingFlags.NonPublic | BindingFlags.Static),
Expression.ArrayIndex(args, Expression.Constant(dateIndex)),
Expression.ArrayIndex(args, Expression.Constant(timeIndex))));
bindings.Add(bdt);
NewExpression n = Expression.New(typeof(W3CEvent));
MemberInitExpression m = Expression.MemberInit(n, bindings.ToArray());
Expression<Func<string[], W3CEvent>> exp = Expression.Lambda<Func<string[], W3CEvent>>(m, ex.Parameters);
return exp;
}
static string MakeIdentifier(string s)
{
return s.Replace('-', '_')
.Replace('(', '_').Replace(')', '_')
.Trim('_');
}
static DateTime ParseDateTime(string date, string time)
{
DateTime dt = DateTime.Parse(date + " " + time);
return dt;
}
}
}