Revize d7aeccba
Přidáno uživatelem Pultak před téměř 3 roky(ů)
ld_client/LDClient/utils/loggers/ALogger.cs | ||
---|---|---|
2 | 2 |
|
3 | 3 |
namespace LDClient.utils.loggers { |
4 | 4 |
|
5 |
/// <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> |
|
5 | 10 |
public abstract class ALogger : IDisposable { |
6 | 11 |
|
12 |
/// <summary> |
|
13 |
/// Logger verbosity type identifies how much information should be actually logged |
|
14 |
/// </summary> |
|
7 | 15 |
private readonly LogVerbosity _verbosity; |
16 |
|
|
17 |
/// <summary> |
|
18 |
/// Current type of logger |
|
19 |
/// </summary> |
|
8 | 20 |
private readonly LogFlow _logFlow; |
9 | 21 |
|
22 |
/// <summary> |
|
23 |
/// Queue of all not yet logged messages |
|
24 |
/// </summary> |
|
10 | 25 |
private readonly Queue<Action> _queue = new(); |
26 |
|
|
27 |
/// <summary> |
|
28 |
/// Synchronization prime used to identify if the is anything new in the queue |
|
29 |
/// </summary> |
|
11 | 30 |
private readonly ManualResetEvent _hasNewItems = new(false); |
31 |
/// <summary> |
|
32 |
/// Synchronization prime used to identify if the logger should be terminated |
|
33 |
/// </summary> |
|
12 | 34 |
private readonly ManualResetEvent _terminate = new(false); |
35 |
/// <summary> |
|
36 |
/// Synchronization prime used to identify if the current thread is waiting |
|
37 |
/// </summary> |
|
13 | 38 |
private readonly ManualResetEvent _waiting = new(false); |
39 |
|
|
40 |
/// <summary> |
|
41 |
/// Thread instance of logging thread |
|
42 |
/// </summary> |
|
14 | 43 |
private readonly Thread _loggingThread; |
15 | 44 |
|
45 |
/// <summary> |
|
46 |
/// Instance of the default logger initialized with the lazy binding mechanism |
|
47 |
/// </summary> |
|
16 | 48 |
private static readonly Lazy<ALogger> LazyLog = new(() |
17 | 49 |
=> { |
18 | 50 |
switch (Program.Config.LogFlowType) { |
... | ... | |
26 | 58 |
} |
27 | 59 |
); |
28 | 60 |
|
61 |
/// <summary> |
|
62 |
/// Instance of the current logger type |
|
63 |
/// </summary> |
|
29 | 64 |
public static ALogger Current => LazyLog.Value; |
30 | 65 |
|
66 |
/// <summary> |
|
67 |
/// Singleton constructor that initialized and starts the logger with arguments parsed by the config loader |
|
68 |
/// </summary> |
|
31 | 69 |
protected ALogger() { |
32 | 70 |
_verbosity = Program.Config.LogVerbosityType; |
33 | 71 |
_logFlow = Program.Config.LogFlowType; |
... | ... | |
35 | 73 |
_loggingThread.Start(); |
36 | 74 |
} |
37 | 75 |
|
76 |
/// <summary> |
|
77 |
/// Creates new log with Info identifier |
|
78 |
/// </summary> |
|
79 |
/// <param name="message">Desired message to be logged</param> |
|
38 | 80 |
public void Info(string message) { |
39 | 81 |
Log(message, LogType.Info); |
40 | 82 |
} |
41 | 83 |
|
84 |
/// <summary> |
|
85 |
/// Creates new log with Debug identifier |
|
86 |
/// </summary> |
|
87 |
/// <param name="message">Desired message to be logged</param> |
|
42 | 88 |
public void Debug(string message) { |
43 | 89 |
Log(message, LogType.Debug); |
44 | 90 |
} |
45 | 91 |
|
92 |
/// <summary> |
|
93 |
/// Creates new log with Error identifier |
|
94 |
/// </summary> |
|
95 |
/// <param name="message">Desired message to be logged</param> |
|
46 | 96 |
public void Error(string message) { |
47 | 97 |
Log(message, LogType.Error); |
48 | 98 |
} |
49 | 99 |
|
100 |
/// <summary> |
|
101 |
/// Creates new log from the catched exception |
|
102 |
/// </summary> |
|
103 |
/// <param name="e">catched exception tha should be logged</param> |
|
50 | 104 |
public void Error(Exception e) { |
51 | 105 |
if (_verbosity != LogVerbosity.None) { |
52 | 106 |
Log(UnwrapExceptionMessages(e), LogType.Error); |
53 | 107 |
} |
54 | 108 |
} |
55 | 109 |
|
110 |
/// <summary> |
|
111 |
/// Creates new string info about current logger configuration |
|
112 |
/// </summary> |
|
113 |
/// <returns></returns> |
|
56 | 114 |
public override string ToString() => $"Logger settings: [Type: {this.GetType().Name}, Verbosity: {_verbosity}, "; |
57 |
|
|
115 |
|
|
58 | 116 |
protected abstract void CreateLog(string message); |
59 | 117 |
|
118 |
/// <summary> |
|
119 |
/// Waits for the logger to finish the logging |
|
120 |
/// </summary> |
|
60 | 121 |
public void Flush() => _waiting.WaitOne(); |
61 | 122 |
|
123 |
/// <summary> |
|
124 |
/// Function stops the logger thread |
|
125 |
/// </summary> |
|
62 | 126 |
public void Dispose() { |
63 | 127 |
_terminate.Set(); |
64 | 128 |
_loggingThread.Join(); |
65 | 129 |
} |
66 | 130 |
|
131 |
/// <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> |
|
67 | 137 |
protected virtual string ComposeLogRow(string message, LogType logType) => |
68 | 138 |
$"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff", CultureInfo.InvariantCulture)} - {logType}] - {message}"; |
69 | 139 |
|
140 |
/// <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> |
|
70 | 145 |
protected virtual string UnwrapExceptionMessages(Exception? ex) => |
71 | 146 |
ex == null ? string.Empty : $"{ex}, Inner exception: {UnwrapExceptionMessages(ex.InnerException)} "; |
72 | 147 |
|
73 |
|
|
148 |
/// <summary> |
|
149 |
/// Function that periodically processes message queue |
|
150 |
/// </summary> |
|
74 | 151 |
private void ProcessQueue() { |
75 | 152 |
while (true) { |
76 | 153 |
_waiting.Set(); |
154 |
//wait until there is new item in the queue or until termination invoked |
|
77 | 155 |
var i = WaitHandle.WaitAny(new WaitHandle[] { _hasNewItems, _terminate }); |
156 |
//was the termination invoked? |
|
78 | 157 |
if (i == 1) return; |
79 | 158 |
_hasNewItems.Reset(); |
80 | 159 |
_waiting.Reset(); |
... | ... | |
91 | 170 |
} |
92 | 171 |
} |
93 | 172 |
|
173 |
/// <summary> |
|
174 |
/// Creates new log string from the current timestamp |
|
175 |
/// </summary> |
|
176 |
/// <param name="message"></param> |
|
177 |
/// <param name="logType"></param> |
|
94 | 178 |
private void Log(string message, LogType logType) { |
95 | 179 |
if (string.IsNullOrEmpty(message)) |
96 | 180 |
return; |
ld_client/LDClient/utils/loggers/ConsoleLogger.cs | ||
---|---|---|
1 | 1 |
namespace LDClient.utils.loggers { |
2 | 2 |
public class ConsoleLogger : ALogger { |
3 |
/// <summary> |
|
4 |
/// CreateLog function for the ConsoleLogger prints the desired message to the console |
|
5 |
/// </summary> |
|
6 |
/// <param name="message">Desired message to be printed</param> |
|
3 | 7 |
protected override void CreateLog(string message) { |
4 | 8 |
Console.WriteLine(message); |
5 | 9 |
} |
ld_client/LDClient/utils/loggers/FileLogger.cs | ||
---|---|---|
4 | 4 |
|
5 | 5 |
public class FileLogger : ALogger { |
6 | 6 |
|
7 |
/// <summary> |
|
8 |
/// Folder name for the created log files |
|
9 |
/// </summary> |
|
7 | 10 |
private const string LogFolderName = "logs"; |
11 |
/// <summary> |
|
12 |
/// Base name of the log file |
|
13 |
/// </summary> |
|
8 | 14 |
private const string LogFileName = "app_info.log"; |
15 |
|
|
9 | 16 |
private readonly int _logChunkSize = Program.Config.LogChunkSize; |
10 | 17 |
private readonly int _logChunkMaxCount = Program.Config.LogChunkMaxCount; |
11 | 18 |
private readonly int _logArchiveMaxCount = Program.Config.LogArchiveMaxCount; |
12 | 19 |
private readonly int _logCleanupPeriod = Program.Config.LogCleanupPeriod; |
13 | 20 |
|
21 |
/// <summary> |
|
22 |
/// Destination folder used to store the created logs and zipped chunks |
|
23 |
/// </summary> |
|
14 | 24 |
private const string LogFolderPath = $"ldClient\\{LogFolderName}"; |
15 | 25 |
|
26 |
/// <summary> |
|
27 |
/// Flag that indicates that the log folder is already created |
|
28 |
/// </summary> |
|
16 | 29 |
private bool _logDirExists; |
17 | 30 |
|
31 |
/// <summary> |
|
32 |
/// Creates one entry in the rotating file. |
|
33 |
/// If the current log file is too big, it creates new log file. |
|
34 |
/// If there is too many log files it archives them. |
|
35 |
/// Deletes all archived files that are too old |
|
36 |
/// </summary> |
|
37 |
/// <param name="message">Desired message to be logged<</param> |
|
18 | 38 |
protected override void CreateLog(string message) { |
19 | 39 |
|
20 | 40 |
if (!_logDirExists) { |
... | ... | |
33 | 53 |
sw.WriteLine(message); |
34 | 54 |
} |
35 | 55 |
|
56 |
/// <summary> |
|
57 |
/// Rotates last log file by creating new logging file in the process |
|
58 |
/// </summary> |
|
59 |
/// <param name="filePath">path to the last log file</param> |
|
36 | 60 |
private void Rotate(string filePath) { |
37 | 61 |
if (!File.Exists(filePath)) { |
38 | 62 |
return; |
... | ... | |
60 | 84 |
DeleteOldArchives(logFolderContent); |
61 | 85 |
} |
62 | 86 |
|
87 |
/// <summary> |
|
88 |
/// Archives the all the last log files (chunks) |
|
89 |
/// </summary> |
|
90 |
/// <param name="chunks">All log files that will be archived</param> |
|
91 |
/// <param name="rotatedPath">path to the log files, which will be archived</param> |
|
92 |
/// <param name="fileTime">current time stamp in string</param> |
|
93 |
/// <param name="folderPath">path to to the exported archives</param> |
|
63 | 94 |
private void Archive(IEnumerable<FileSystemInfo> chunks, string rotatedPath, string fileTime, string? folderPath) { |
64 | 95 |
|
65 | 96 |
var archiveFolderInfo = Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(rotatedPath) ?? LogFolderPath, $"{LogFolderName}_{fileTime}")); |
... | ... | |
73 | 104 |
Directory.Delete(archiveFolderInfo.FullName, true); |
74 | 105 |
} |
75 | 106 |
|
107 |
/// <summary> |
|
108 |
/// This function deletes all archives that are too old and exceeds the maximum zip files. |
|
109 |
/// Cleanup period and zip max count can be specified in the configuration file. |
|
110 |
/// </summary> |
|
111 |
/// <param name="logFolderContent">filesystem info of the log folder</param> |
|
76 | 112 |
private void DeleteOldArchives(FileSystemInfo[] logFolderContent) { |
77 | 113 |
|
78 | 114 |
var archives = logFolderContent.Where(x => x.Extension.Equals(".zip", StringComparison.OrdinalIgnoreCase)).ToArray(); |
79 |
|
|
115 |
|
|
80 | 116 |
if (archives.Length <= _logArchiveMaxCount) |
81 | 117 |
return; |
82 | 118 |
|
119 |
//find oldest archive in the folder |
|
83 | 120 |
var oldestArchive = archives.OrderBy(x => x.CreationTime).First(); |
84 | 121 |
var cleanupDate = oldestArchive.CreationTime.AddDays(_logCleanupPeriod); |
122 |
//is there any file older than specified cleanup cleanup period |
|
85 | 123 |
if (DateTime.Compare(cleanupDate, DateTime.Now) <= 0) { |
86 | 124 |
foreach (var file in logFolderContent) { |
87 | 125 |
file.Delete(); |
... | ... | |
90 | 128 |
File.Delete(oldestArchive.FullName); |
91 | 129 |
} |
92 | 130 |
} |
93 |
|
|
94 | 131 |
public override string ToString() => $"{base.ToString()}, Chunk Size: {_logChunkSize}, Max chunk count: {_logChunkMaxCount}, Max log archive count: {_logArchiveMaxCount}, Cleanup period: {_logCleanupPeriod} days]"; |
95 | 132 |
} |
ld_client/LDClient/utils/loggers/LogFlow.cs | ||
---|---|---|
1 | 1 |
namespace LDClient.utils.loggers { |
2 |
/// <summary> |
|
3 |
/// This enum specifies all possible types of loggers |
|
4 |
/// </summary> |
|
2 | 5 |
public enum LogFlow { |
6 |
/// <summary> |
|
7 |
/// Console logger |
|
8 |
/// </summary> |
|
3 | 9 |
Console = 0, |
10 |
/// <summary> |
|
11 |
/// Rotating file logger |
|
12 |
/// </summary> |
|
4 | 13 |
File |
5 | 14 |
} |
6 | 15 |
} |
ld_client/LDClient/utils/loggers/LogType.cs | ||
---|---|---|
1 | 1 |
namespace LDClient.utils.loggers { |
2 |
/// <summary> |
|
3 |
/// Types of all possible logs |
|
4 |
/// </summary> |
|
2 | 5 |
public enum LogType { |
3 | 6 |
Info = 0, |
4 | 7 |
Debug, |
ld_client/LDClient/utils/loggers/LogVerbosity.cs | ||
---|---|---|
1 | 1 |
namespace LDClient.utils.loggers { |
2 |
|
|
3 |
/// <summary> |
|
4 |
/// Enum specifies the verbosity of the log messages |
|
5 |
/// </summary> |
|
2 | 6 |
public enum LogVerbosity { |
3 | 7 |
None = 0, |
4 | 8 |
Exceptions, |
Také k dispozici: Unified diff
re #9570 Added code documentation to logger classes and properties