Projekt

Obecné

Profil

Stáhnout (6.75 KB) Statistiky
| Větev: | Tag: | Revize:
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
}