1 |
74bd1e40
|
Pultak
|
using System.Globalization;
|
2 |
|
|
|
3 |
|
|
namespace LDClient.utils.loggers {
|
4 |
|
|
|
5 |
d7aeccba
|
Pultak
|
/// <summary>
|
6 |
|
|
/// This class implements all abstract functions of the logger.
|
7 |
|
|
/// It contains all functions (error, info, debug) that are present in any other standard logger.
|
8 |
|
|
/// Class is used as singleton design pattern
|
9 |
|
|
/// </summary>
|
10 |
74bd1e40
|
Pultak
|
public abstract class ALogger : IDisposable {
|
11 |
|
|
|
12 |
d7aeccba
|
Pultak
|
/// <summary>
|
13 |
|
|
/// Logger verbosity type identifies how much information should be actually logged
|
14 |
|
|
/// </summary>
|
15 |
74bd1e40
|
Pultak
|
private readonly LogVerbosity _verbosity;
|
16 |
d7aeccba
|
Pultak
|
|
17 |
|
|
/// <summary>
|
18 |
|
|
/// Current type of logger
|
19 |
|
|
/// </summary>
|
20 |
74bd1e40
|
Pultak
|
private readonly LogFlow _logFlow;
|
21 |
|
|
|
22 |
d7aeccba
|
Pultak
|
/// <summary>
|
23 |
|
|
/// Queue of all not yet logged messages
|
24 |
|
|
/// </summary>
|
25 |
74bd1e40
|
Pultak
|
private readonly Queue<Action> _queue = new();
|
26 |
d7aeccba
|
Pultak
|
|
27 |
|
|
/// <summary>
|
28 |
|
|
/// Synchronization prime used to identify if the is anything new in the queue
|
29 |
|
|
/// </summary>
|
30 |
74bd1e40
|
Pultak
|
private readonly ManualResetEvent _hasNewItems = new(false);
|
31 |
d7aeccba
|
Pultak
|
/// <summary>
|
32 |
|
|
/// Synchronization prime used to identify if the logger should be terminated
|
33 |
|
|
/// </summary>
|
34 |
74bd1e40
|
Pultak
|
private readonly ManualResetEvent _terminate = new(false);
|
35 |
d7aeccba
|
Pultak
|
/// <summary>
|
36 |
|
|
/// Synchronization prime used to identify if the current thread is waiting
|
37 |
|
|
/// </summary>
|
38 |
74bd1e40
|
Pultak
|
private readonly ManualResetEvent _waiting = new(false);
|
39 |
d7aeccba
|
Pultak
|
|
40 |
|
|
/// <summary>
|
41 |
|
|
/// Thread instance of logging thread
|
42 |
|
|
/// </summary>
|
43 |
74bd1e40
|
Pultak
|
private readonly Thread _loggingThread;
|
44 |
|
|
|
45 |
d7aeccba
|
Pultak
|
/// <summary>
|
46 |
|
|
/// Instance of the default logger initialized with the lazy binding mechanism
|
47 |
|
|
/// </summary>
|
48 |
74bd1e40
|
Pultak
|
private static readonly Lazy<ALogger> LazyLog = new(()
|
49 |
|
|
=> {
|
50 |
|
|
switch (Program.Config.LogFlowType) {
|
51 |
|
|
case LogFlow.File:
|
52 |
|
|
return new FileLogger();
|
53 |
|
|
case LogFlow.Console:
|
54 |
|
|
default:
|
55 |
|
|
return new ConsoleLogger();
|
56 |
|
|
|
57 |
|
|
}
|
58 |
|
|
}
|
59 |
|
|
);
|
60 |
|
|
|
61 |
d7aeccba
|
Pultak
|
/// <summary>
|
62 |
|
|
/// Instance of the current logger type
|
63 |
|
|
/// </summary>
|
64 |
74bd1e40
|
Pultak
|
public static ALogger Current => LazyLog.Value;
|
65 |
|
|
|
66 |
d7aeccba
|
Pultak
|
/// <summary>
|
67 |
|
|
/// Singleton constructor that initialized and starts the logger with arguments parsed by the config loader
|
68 |
|
|
/// </summary>
|
69 |
74bd1e40
|
Pultak
|
protected ALogger() {
|
70 |
|
|
_verbosity = Program.Config.LogVerbosityType;
|
71 |
|
|
_logFlow = Program.Config.LogFlowType;
|
72 |
|
|
_loggingThread = new Thread(ProcessQueue) { IsBackground = true };
|
73 |
|
|
_loggingThread.Start();
|
74 |
|
|
}
|
75 |
|
|
|
76 |
d7aeccba
|
Pultak
|
/// <summary>
|
77 |
|
|
/// Creates new log with Info identifier
|
78 |
|
|
/// </summary>
|
79 |
|
|
/// <param name="message">Desired message to be logged</param>
|
80 |
74bd1e40
|
Pultak
|
public void Info(string message) {
|
81 |
|
|
Log(message, LogType.Info);
|
82 |
|
|
}
|
83 |
|
|
|
84 |
d7aeccba
|
Pultak
|
/// <summary>
|
85 |
|
|
/// Creates new log with Debug identifier
|
86 |
|
|
/// </summary>
|
87 |
|
|
/// <param name="message">Desired message to be logged</param>
|
88 |
74bd1e40
|
Pultak
|
public void Debug(string message) {
|
89 |
|
|
Log(message, LogType.Debug);
|
90 |
|
|
}
|
91 |
|
|
|
92 |
d7aeccba
|
Pultak
|
/// <summary>
|
93 |
|
|
/// Creates new log with Error identifier
|
94 |
|
|
/// </summary>
|
95 |
|
|
/// <param name="message">Desired message to be logged</param>
|
96 |
74bd1e40
|
Pultak
|
public void Error(string message) {
|
97 |
|
|
Log(message, LogType.Error);
|
98 |
|
|
}
|
99 |
|
|
|
100 |
d7aeccba
|
Pultak
|
/// <summary>
|
101 |
|
|
/// Creates new log from the catched exception
|
102 |
|
|
/// </summary>
|
103 |
|
|
/// <param name="e">catched exception tha should be logged</param>
|
104 |
74bd1e40
|
Pultak
|
public void Error(Exception e) {
|
105 |
|
|
if (_verbosity != LogVerbosity.None) {
|
106 |
|
|
Log(UnwrapExceptionMessages(e), LogType.Error);
|
107 |
|
|
}
|
108 |
|
|
}
|
109 |
|
|
|
110 |
d7aeccba
|
Pultak
|
/// <summary>
|
111 |
|
|
/// Creates new string info about current logger configuration
|
112 |
|
|
/// </summary>
|
113 |
|
|
/// <returns></returns>
|
114 |
74bd1e40
|
Pultak
|
public override string ToString() => $"Logger settings: [Type: {this.GetType().Name}, Verbosity: {_verbosity}, ";
|
115 |
d7aeccba
|
Pultak
|
|
116 |
74bd1e40
|
Pultak
|
protected abstract void CreateLog(string message);
|
117 |
|
|
|
118 |
d7aeccba
|
Pultak
|
/// <summary>
|
119 |
|
|
/// Waits for the logger to finish the logging
|
120 |
|
|
/// </summary>
|
121 |
74bd1e40
|
Pultak
|
public void Flush() => _waiting.WaitOne();
|
122 |
|
|
|
123 |
d7aeccba
|
Pultak
|
/// <summary>
|
124 |
|
|
/// Function stops the logger thread
|
125 |
|
|
/// </summary>
|
126 |
74bd1e40
|
Pultak
|
public void Dispose() {
|
127 |
|
|
_terminate.Set();
|
128 |
|
|
_loggingThread.Join();
|
129 |
|
|
}
|
130 |
|
|
|
131 |
d7aeccba
|
Pultak
|
/// <summary>
|
132 |
|
|
/// Composes the log with actual timestamp, log type and its main message
|
133 |
|
|
/// </summary>
|
134 |
|
|
/// <param name="message">main message of the log</param>
|
135 |
|
|
/// <param name="logType">Type of the logged message</param>
|
136 |
|
|
/// <returns></returns>
|
137 |
74bd1e40
|
Pultak
|
protected virtual string ComposeLogRow(string message, LogType logType) =>
|
138 |
|
|
$"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff", CultureInfo.InvariantCulture)} - {logType}] - {message}";
|
139 |
|
|
|
140 |
d7aeccba
|
Pultak
|
/// <summary>
|
141 |
|
|
/// Function creates log from the catched exception
|
142 |
|
|
/// </summary>
|
143 |
|
|
/// <param name="ex">catched exception tha should be logged</param>
|
144 |
|
|
/// <returns></returns>
|
145 |
74bd1e40
|
Pultak
|
protected virtual string UnwrapExceptionMessages(Exception? ex) =>
|
146 |
|
|
ex == null ? string.Empty : $"{ex}, Inner exception: {UnwrapExceptionMessages(ex.InnerException)} ";
|
147 |
|
|
|
148 |
d7aeccba
|
Pultak
|
/// <summary>
|
149 |
|
|
/// Function that periodically processes message queue
|
150 |
|
|
/// </summary>
|
151 |
74bd1e40
|
Pultak
|
private void ProcessQueue() {
|
152 |
|
|
while (true) {
|
153 |
|
|
_waiting.Set();
|
154 |
d7aeccba
|
Pultak
|
//wait until there is new item in the queue or until termination invoked
|
155 |
74bd1e40
|
Pultak
|
var i = WaitHandle.WaitAny(new WaitHandle[] { _hasNewItems, _terminate });
|
156 |
d7aeccba
|
Pultak
|
//was the termination invoked?
|
157 |
74bd1e40
|
Pultak
|
if (i == 1) return;
|
158 |
|
|
_hasNewItems.Reset();
|
159 |
|
|
_waiting.Reset();
|
160 |
|
|
|
161 |
|
|
Queue<Action> queueCopy;
|
162 |
|
|
lock (_queue) {
|
163 |
|
|
queueCopy = new Queue<Action>(_queue);
|
164 |
|
|
_queue.Clear();
|
165 |
|
|
}
|
166 |
|
|
|
167 |
|
|
foreach (var log in queueCopy) {
|
168 |
|
|
log();
|
169 |
|
|
}
|
170 |
|
|
}
|
171 |
|
|
}
|
172 |
|
|
|
173 |
d7aeccba
|
Pultak
|
/// <summary>
|
174 |
|
|
/// Creates new log string from the current timestamp
|
175 |
|
|
/// </summary>
|
176 |
|
|
/// <param name="message"></param>
|
177 |
|
|
/// <param name="logType"></param>
|
178 |
74bd1e40
|
Pultak
|
private void Log(string message, LogType logType) {
|
179 |
|
|
if (string.IsNullOrEmpty(message))
|
180 |
|
|
return;
|
181 |
|
|
|
182 |
|
|
var logRow = ComposeLogRow(message, logType);
|
183 |
|
|
System.Diagnostics.Debug.WriteLine(logRow);
|
184 |
|
|
|
185 |
|
|
if (_verbosity == LogVerbosity.Full) {
|
186 |
|
|
lock (_queue)
|
187 |
|
|
_queue.Enqueue(() => CreateLog(logRow));
|
188 |
|
|
|
189 |
|
|
_hasNewItems.Set();
|
190 |
|
|
}
|
191 |
|
|
}
|
192 |
|
|
}
|
193 |
|
|
}
|