Last active
August 29, 2015 13:56
-
-
Save ryanohs/8854835 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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