Skip to content

Instantly share code, notes, and snippets.

@ryanohs
Last active August 29, 2015 13:56
Show Gist options
  • Save ryanohs/8854835 to your computer and use it in GitHub Desktop.
Save ryanohs/8854835 to your computer and use it in GitHub Desktop.
using System;
using System.IO;
public class LogSearcher
{
public static int DateLength = "2013-12-29 17:37:56".Length;
public void Search(string path, DateTime start, DateTime end, TextWriter results)
{
using (var file = File.Open(path, FileMode.Open))
using (var reader = new StreamReader(file))
{
var startOfSearchRegion = 0L;
var endOfSearchRegion = file.Length - 1;
var offset = endOfSearchRegion/2;
var lastOffset = offset;
while (true)
{
string line = ReadLineAt(reader, ref offset); // offset is moved to start of line
while (line[0] == '#' && offset > 0)
{
--offset;
line = ReadLineAt(reader, ref offset); // offset is moved to start of line
}
if(offset == 0)
{
break;
}
var date = DateTime.Parse(line.Substring(0, DateLength));
if (date < start)
{
startOfSearchRegion = offset;
}
else
{
endOfSearchRegion = offset;
}
if (lastOffset == offset)
{
break;
}
lastOffset = offset;
offset = (startOfSearchRegion + endOfSearchRegion)/2;
}
// Now just read until we reach the end date or EOF
reader.BaseStream.Seek(offset, SeekOrigin.Begin);
reader.DiscardBufferedData();
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if (line[0] == '#' || line.Length < DateLength)
{
results.WriteLine(line);
}
else
{
var date = DateTime.Parse(line.Substring(0, DateLength));
if (date < start) continue;
if (date > end) break;
results.WriteLine(line);
}
}
}
}
// This function will move the offset backwards until we get to the begininning of the current line.
// I'm seeking backwards because otherwise we'll never get the first line!
// ex: The computed offset could initially be at the ^ in this snippet of data:
// "\n2013-12-29 17:37:56 127.0.0.1 GET /test - 8^0 - 127.0.0.1\n"
private static string ReadLineAt(StreamReader reader, ref long offset)
{
reader.BaseStream.Seek(offset, SeekOrigin.Begin);
reader.DiscardBufferedData();
if (offset == 0)
{
return reader.ReadLine();
}
do
{
// can't rely on reader.BaseStream.Position or SeekOrigin.Current due to buffering.
reader.BaseStream.Seek(--offset, SeekOrigin.Begin);
reader.DiscardBufferedData();
} while (reader.Peek() != '\n' && offset != 0);
if (offset > 0)
{
reader.BaseStream.Seek(++offset, SeekOrigin.Begin);
reader.DiscardBufferedData();
}
return reader.ReadLine();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment