6 open System.Diagnostics
8 open System.Collections.Generic
10 type Severity = DEBUG = 1 | USER = 2 | WARNING = 3 | ERROR = 4 | FATAL = 5
12 type IListener = abstract NewEntry : Severity -> string -> unit
16 let maxSizeFile = 10L * 1024L * 1024L // [byte] (10 MB).
17 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'.
18 let LogDefaultDirectory = "Parasitemia\\Log"
19 let filenameFormat = "{0:D4}.log"
20 let encoding = Encoding.GetEncoding("UTF-8")
22 let moduleName = System.Diagnostics.StackFrame(1).GetMethod().Module.Name
24 let mutable stream: StreamWriter = null
26 let mutable logDir: string = null
27 let mutable absoluteDir: string = null
29 let mutable nbEntries = 0L
31 let monitor = Object()
33 let listeners = List<IListener>()
42 static let instance = new Log()
44 let setLogDirectory (dir
: string) =
45 lock
monitor (fun () ->
47 absoluteDir <- Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), logDir)
55 if not
<| Directory.Exists(absoluteDir)
57 Directory.CreateDirectory(absoluteDir) |> ignore
59 | _ as ex -> Console.Error.WriteLine("Unable to create the log directory: {0}", absoluteDir))
63 if stream = null || (nbEntries % (int64
nbEntriesCheckSize) = 0L) && stream.BaseStream.Length > maxSizeFile
70 for existingFile
in Directory.GetFiles(absoluteDir) do
72 if Int32.TryParse(existingFile
.Remove(existingFile
.LastIndexOf('.')), current_n) && !current_n > n
76 let mutable filename = Path.Combine(absoluteDir, String.Format(filenameFormat, n))
78 if (FileInfo(filename).Length > maxSizeFile)
80 filename <- Path.Combine(absoluteDir, String.Format(filenameFormat, n + 1))
82 | :? FileNotFoundException -> () // The file may not exist.
84 stream <- new StreamWriter(filename, true, encoding)
86 | _ as ex -> Console.Error.WriteLine("Can't open the file log: {0}", ex)
89 setLogDirectory LogDefaultDirectory
91 interface IDisposable with
92 member this
.Dispose () =
97 member private
this.Write (message
: string, severity
: Severity) =
98 lock
monitor (fun () ->
99 nbEntries <- nbEntries + 1L
104 let mutable moduleNameCaller = moduleName
105 match StackTrace().GetFrames() |> Array.tryPick
(fun frame
-> let name = frame
.GetMethod().Module.Name
106 if name <> moduleName then Some name else None) with
107 | Some name -> moduleNameCaller <- name
110 let threadName = Thread.CurrentThread.Name
112 for listener
in listeners do
113 listener
.NewEntry severity message
117 "{0:yyyy-MM-dd HH:mm:ss.fff} [{1}] {{{2}}} ({3}) : {4}",
118 TimeZone.CurrentTimeZone.ToLocalTime(DateTime.UtcNow),
121 (if String.IsNullOrEmpty(threadName) then Thread.CurrentThread.ManagedThreadId.ToString() else String.Format("{0}-{1}", threadName, Thread.CurrentThread.ManagedThreadId)),
126 | :? IOException as ex -> Console.Error.WriteLine("Unable to write to the log file: {0}", ex))
129 member private
this.AddListener (listener
: IListener) =
130 lock
monitor (fun () ->
131 if not
<| listeners.Contains(listener
)
133 listeners.Add(listener
))
135 member private
this.RmListener (listener
: IListener) =
136 lock
monitor (fun () ->
137 listeners.Remove(listener
) |> ignore
)
139 static member AddListener (listener
: IListener) = instance.AddListener(listener
)
140 static member RmListener (listener
: IListener) = instance.RmListener(listener
)
142 static member LogWithTime (message
: string, severity
: Severity, f
: unit -> 'a, [<ParamArray>] args: Object[]) : 'a
=
147 instance.Write(String.Format(message
, args
) + sprintf
" (time: %d ms)" sw.ElapsedMilliseconds, severity
)
150 static member Debug (message
: string, [<ParamArray>] args
: Object[]) =
152 instance.Write(String.Format(message
, args
), Severity.DEBUG)
157 static member User (message
: string, [<ParamArray>] args
: Object[]) =
158 instance.Write(String.Format(message
, args
), Severity.USER)
160 static member Warning (message
: string, [<ParamArray>] args
: Object[]) =
161 instance.Write(String.Format(message
, args
), Severity.WARNING)
163 static member Error (message
: string, [<ParamArray>] args
: Object[]) =
164 instance.Write(String.Format(message
, args
), Severity.ERROR)
166 static member Fatal (message
: string, [<ParamArray>] args
: Object[]) =
167 instance.Write(String.Format(message
, args
), Severity.FATAL)