Created
March 16, 2020 21:44
-
-
Save medigor/5bc16e9166b788861dcdf420ac9b55a6 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
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