Skip to content

Instantly share code, notes, and snippets.

@medigor
Created March 16, 2020 21:44
Show Gist options
  • Save medigor/5bc16e9166b788861dcdf420ac9b55a6 to your computer and use it in GitHub Desktop.
Save medigor/5bc16e9166b788861dcdf420ac9b55a6 to your computer and use it in GitHub Desktop.
module Parser
open System
open System.IO
open System.Text
open System.Text.RegularExpressions
open FSharp.Control.AsyncSeqExtensions
open FSharp.Control
type Event = {
Date: DateTime
Duration: uint32
Name: string
Level: uint32
Process: string
Properties: array<string * string> }
with
override this.ToString() =
let date = this.Date.ToString("dd.MM.yyyy HH:mm:ss.ffffff")
sprintf "%s-%i,%s,%s" date this.Duration this.Name this.Process
let readToDelimiter (sr: StreamReader, delimiter: char, buffer: StringBuilder, endOfLine: byref<bool>) =
endOfLine <- false
let mutable c = sr.Read();
if c = int('"') || c = int('\'') then
let quote = c // Запомнить кавычку, но в буфер не нужно помещать.
c <- sr.Read()
while c <> -1 do
if c = quote then
if sr.Peek() = quote then
// Значит двойная кавычка, одна должна быть пропущена
sr.Read() |> ignore
else
// Значит это одинарная кавычка
c <- -1
if c <> -1 then
buffer.Append(char c) |> ignore
c <- sr.Read()
// Удалить перевод строки
let p = sr.Peek()
if p = int delimiter then
sr.Read() |> ignore
else if p = 13 then
sr.Read() |> ignore
if sr.Peek() = 10 then
sr.Read() |> ignore
endOfLine <- true
else
while c <> -1 && c <> int delimiter do
if c = 13 then
endOfLine <- true
if sr.Peek() = 10 then
sr.Read() |> ignore
c <- -1
else
buffer.Append((char)c) |> ignore
c <- sr.Read()
let retValue = buffer.ToString()
buffer.Clear() |> ignore
retValue
let parse(date: DateTime, sr: StreamReader, buffer: StringBuilder): Event =
let mutable endOfLine = false
let minutes = readToDelimiter(sr, ':', buffer, &endOfLine)
let seconds = readToDelimiter(sr, '.', buffer, &endOfLine)
let microSeconds = readToDelimiter(sr, '-', buffer, &endOfLine)
let duration = readToDelimiter(sr, ',', buffer, &endOfLine)
let name = readToDelimiter(sr, ',', buffer, &endOfLine).ToUpper()
let level = readToDelimiter(sr, ',', buffer, &endOfLine)
let mutable process' = ""
let properties = [|
while (not endOfLine && not sr.EndOfStream) do
let name = readToDelimiter(sr, '=', buffer, &endOfLine)
let value = readToDelimiter(sr, ',', buffer, &endOfLine)
if name = "process" then process' <- value
name, value
|]
{
Date = date.AddMinutes(float minutes).AddSeconds(float seconds).AddTicks((int64 microSeconds) * 10L)
Duration = uint32 duration
Name = name
Level = uint32 level
Process = process'
Properties = properties
}
let getEvents(fileName: string) =
seq {
let info = FileInfo fileName
if not info.Exists then
FileNotFoundException(fileName) |> raise
if not (Regex.IsMatch(info.Name, @"\d{8}\.log$")) then
ArgumentException("Invalid format filename") |> raise
let year = 2000 + (int (info.Name.Substring(0, 2)))
let month = int (info.Name.Substring(2, 2))
let day = int (info.Name.Substring(4, 2))
let hour = int (info.Name.Substring(6, 2))
let date = DateTime(year, month, day, hour, 0, 0)
let buffer = StringBuilder(4096 * 128)
use fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
use sr = new StreamReader(fs, Encoding.UTF8, true, 4096 * 1024)
while not sr.EndOfStream do
parse(date, sr, buffer)
}
let getEventsAsync(fileName: string) =
asyncSeq {
let info = FileInfo fileName
if not info.Exists then
FileNotFoundException(fileName) |> raise
if not (Regex.IsMatch(info.Name, @"\d{8}\.log$")) then
ArgumentException("Invalid format filename") |> raise
let year = 2000 + (int (info.Name.Substring(0, 2)))
let month = int (info.Name.Substring(2, 2))
let day = int (info.Name.Substring(4, 2))
let hour = int (info.Name.Substring(6, 2))
let date = DateTime(year, month, day, hour, 0, 0)
let buffer = StringBuilder(4096 * 128)
use fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
use sr = new StreamReader(fs, Encoding.UTF8, true, 4096 * 1024)
while not sr.EndOfStream do
parse(date, sr, buffer)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment