Snippets
Created by
Tuomas Hietanen
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | #if INTERACTIVE
#else
module LogReader
#endif
//Log file parser for log4Net files.
open System
open System.IO
type CollectData =
| NotIntresting
| SeekStackTraceLine of string
| SeekCompanyStackTraceLine of string * string
///Log4Net item separator
[<Literal>]
let separator = "$$"
///Beginig for a normal line. e.g. date like 2013-10-27
[<Literal>]
let normalLineBegin = "201"
///Company namespace in the stacktrace
[<Literal>]
let companyStackTraceSign = "MyCompany"
///Detect error line in the log: contains this string
let errorsign = separator + "ERROR" + separator
///This will parse the lines to resultset of errors
let collectErrorInfo lines =
let rec readLines (myLines:string list) (mode:CollectData) resultdata =
// Add current findings to collection, just in case
let collectedResult =
match mode with
| NotIntresting -> resultdata
| SeekStackTraceLine(a) ->
let info = "No-StackTrace", "", a
(info::resultdata)
| SeekCompanyStackTraceLine(a, b) ->
let info = "Non-"+companyStackTraceSign+"-StackTrace", a, b
(info::resultdata)
match myLines, mode with
//New error-line: try to seek stacktrace, store current findings
| h::t, _ when h.StartsWith(normalLineBegin) && h.Contains(errorsign) ->
readLines t (SeekStackTraceLine(h)) collectedResult
//New info-line: dont seek stacktrace, store current findings
| h::t, _ when h.StartsWith(normalLineBegin) && not (h.Contains(errorsign)) ->
readLines t NotIntresting collectedResult
//New stacktrace-line: try to seek Company-stack, dont store yet
| h::t, SeekStackTraceLine(l) when not (h.StartsWith(normalLineBegin)) ->
readLines t (SeekCompanyStackTraceLine(h, l)) resultdata
//New Company-stack-line: everything ok, lets store the result and continue
| h::t, SeekCompanyStackTraceLine(a, b) when not (h.StartsWith(normalLineBegin)) && h.Contains(companyStackTraceSign) ->
readLines t NotIntresting collectedResult
//All the other cases: continue to next line
| h::t, _ -> readLines t mode resultdata
//End of file: return all with the last one
| [], _ -> collectedResult
readLines (lines |> Seq.toList) NotIntresting []
///Function to break-down lines by separator.
///e.g. for csv-import: by default Excel doesn't support multiple character separators
let breakLineDetails mySeq =
let breakLineDetail (a,b,c:string) =
a,b,c.Split([|separator|],StringSplitOptions.None)
mySeq |> Seq.map breakLineDetail
let filesByPath path = Directory.EnumerateFiles(path,"*.log*",SearchOption.AllDirectories)
open System.Linq
/// This will read the file, parse it and give results.
let processFiles files =
let result =
files
|> Seq.map (fun (fileOrPath:string) ->
match fileOrPath with
| path when path.EndsWith(@"\") || path.EndsWith(@"/") -> // gist highlight fix"
filesByPath path |> Seq.map File.ReadLines |> Seq.concat
| file -> File.ReadLines file)
|> Seq.concat
|> collectErrorInfo
|> breakLineDetails
result.GroupBy(fun (a,b,c) -> a + " " + b).OrderByDescending(fun k -> k.Count())
///For console program, we can use this
// For good UI we would input fileName and output results
// (results is a grouped list of errors by type)
[<EntryPoint>]
let main argv =
let filtered = argv |> Array.filter (fun i -> not (i = ""))
match filtered with
| [||] -> printfn "Please input filename as argument."
| fileNames ->
//let fileNames = [|@"C:\...\MyProgram.log"|]
let results = processFiles fileNames
for i in results
do Console.WriteLine("Count: " + i.Count().ToString() + ", Item: " + i.Key)
0 // return an integer exit code
|
Comments (0)
You can clone a snippet to your computer for local editing. Learn more.