X-Git-Url: http://git.euphorik.ch/?a=blobdiff_plain;f=Parasitemia%2FLogger%2FLogger.fs;fp=Parasitemia%2FLogger%2FLogger.fs;h=552e37dd1e5859590a6826a6b82bbed3caaf50f5;hb=4bfa3cbdc6145e6944f02e24829ab2ef3a851ac1;hp=0000000000000000000000000000000000000000;hpb=48ecdfc43001c444eff6ad442986049384674af2;p=master-thesis.git diff --git a/Parasitemia/Logger/Logger.fs b/Parasitemia/Logger/Logger.fs new file mode 100644 index 0000000..552e37d --- /dev/null +++ b/Parasitemia/Logger/Logger.fs @@ -0,0 +1,168 @@ +namespace Logger + +open System +open System.Text +open System.IO +open System.Diagnostics +open System.Threading +open System.Collections.Generic + +type Severity = DEBUG = 1 | USER = 2 | WARNING = 3 | ERROR = 4 | FATAL = 5 + +type IListener = abstract NewEntry : Severity -> string -> unit + +[] +type Log () = + let maxSizeFile = 10L * 1024L * 1024L // [byte] (10 MB). + let nbEntriesCheckSize = 100; // Each 100 entries added we check the size of the log file to test if it is greater than 'MAX_SIZE_FILE'. + let LogDefaultDirectory = "Parasitemia\\Log" + let filenameFormat = "{0:D4}.log" + let encoding = Encoding.GetEncoding("UTF-8") + + let moduleName = System.Diagnostics.StackFrame(1).GetMethod().Module.Name + + let mutable stream: StreamWriter = null + + let mutable logDir: string = null + let mutable absoluteDir: string = null + + let mutable nbEntries = 0L + + let monitor = Object() + + let listeners = List() + + let debug = +#if DEBUG + true +#else + false +#endif + + static let instance = new Log() + + let setLogDirectory (dir: string) = + lock monitor (fun () -> + logDir <- dir + absoluteDir <- Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), logDir) + + if stream <> null + then + stream.Close() + stream <- null + + try + if not <| Directory.Exists(absoluteDir) + then + Directory.CreateDirectory(absoluteDir) |> ignore + with + | _ as ex -> Console.Error.WriteLine("Unable to create the log directory: {0}", absoluteDir)) + + let openLogFile () = + try + if stream = null || (nbEntries % (int64 nbEntriesCheckSize) = 0L) && stream.BaseStream.Length > maxSizeFile + then + if stream <> null + then + stream.Close() + + let mutable n = 1 + for existingFile in Directory.GetFiles(absoluteDir) do + let current_n = ref 0 + if Int32.TryParse(existingFile.Remove(existingFile.LastIndexOf('.')), current_n) && !current_n > n + then + n <- !current_n + + let mutable filename = Path.Combine(absoluteDir, String.Format(filenameFormat, n)) + try + if (FileInfo(filename).Length > maxSizeFile) + then + filename <- Path.Combine(absoluteDir, String.Format(filenameFormat, n + 1)) + with + | :? FileNotFoundException -> () // The file may not exist. + + stream <- new StreamWriter(filename, true, encoding) + with + | _ as ex -> Console.Error.WriteLine("Can't open the file log: {0}", ex) + + do + setLogDirectory LogDefaultDirectory + + interface IDisposable with + member this.Dispose () = + if stream <> null + then + stream.Dispose() + + member private this.Write (message: string, severity: Severity) = + lock monitor (fun () -> + nbEntries <- nbEntries + 1L + openLogFile () + + if stream <> null + then + let mutable moduleNameCaller = moduleName + match StackTrace().GetFrames() |> Array.tryPick (fun frame -> let name = frame.GetMethod().Module.Name + if name <> moduleName then Some name else None) with + | Some name -> moduleNameCaller <- name + | _ -> () + + let threadName = Thread.CurrentThread.Name + + for listener in listeners do + listener.NewEntry severity message + + try + stream.WriteLine( + "{0:yyyy-MM-dd HH:mm:ss.fff} [{1}] {{{2}}} ({3}) : {4}", + TimeZone.CurrentTimeZone.ToLocalTime(DateTime.UtcNow), + severity.ToString(), + moduleNameCaller, + (if String.IsNullOrEmpty(threadName) then Thread.CurrentThread.ManagedThreadId.ToString() else String.Format("{0}-{1}", threadName, Thread.CurrentThread.ManagedThreadId)), + message + ) + stream.Flush() + with + | :? IOException as ex -> Console.Error.WriteLine("Unable to write to the log file: {0}", ex)) + + + member private this.AddListener (listener: IListener) = + lock monitor (fun () -> + if not <| listeners.Contains(listener) + then + listeners.Add(listener)) + + member private this.RmListener (listener: IListener) = + lock monitor (fun () -> + listeners.Remove(listener) |> ignore) + + static member AddListener (listener: IListener) = instance.AddListener(listener) + static member RmListener (listener: IListener) = instance.RmListener(listener) + + static member LogWithTime (message: string, severity: Severity, f: unit -> 'a, [] args: Object[]) : 'a = + let sw = Stopwatch() + sw.Start() + let res = f () + sw.Stop() + instance.Write(String.Format(message, args) + sprintf " (time: %d ms)" sw.ElapsedMilliseconds, severity) + res + + static member Debug (message: string, [] args: Object[]) = +#if DEBUG + instance.Write(String.Format(message, args), Severity.DEBUG) +#else + () +#endif + + static member User (message: string, [] args: Object[]) = + instance.Write(String.Format(message, args), Severity.USER) + + static member Warning (message: string, [] args: Object[]) = + instance.Write(String.Format(message, args), Severity.WARNING) + + static member Error (message: string, [] args: Object[]) = + instance.Write(String.Format(message, args), Severity.ERROR) + + static member Fatal (message: string, [] args: Object[]) = + instance.Write(String.Format(message, args), Severity.FATAL) +