Projekt

Obecné

Profil

« Předchozí | Další » 

Revize 71520576

Přidáno uživatelem Pultak před více než 2 roky(ů)

re #9439 Implementation of console and rotating file logger

Zobrazit rozdíly:

ld_client/LDClient/Program.cs
1
using System;
1
using LDClient;
2
using System;
2 3

  
3 4

  
4 5
class Program {
5 6

  
7
    public static LDClient.ConfigLoader Config { get; set; }
8

  
6 9
    // Main Method
7 10
    static public void Main() {
11
        Config = new LDClient.ConfigLoader();
8 12

  
9
        Console.WriteLine("Main Method");
13
        while (true) {
14
            Logger.Current.Info("Ok");
15
            Logger.Current.Debug("Debug");
16
            Logger.Current.Error("Error");
17
        }
10 18
    }
11 19
}
ld_client/LDClient/utils/Logger.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Globalization;
4
using System.IO.Compression;
5
using System.Linq;
6
using System.Text;
7
using System.Threading.Tasks;
8

  
9
namespace LDClient {
10
    enum LogVerbosity {
11
        None = 0,
12
        Exceptions,
13
        Full
14
    }
15

  
16
    public enum LogType {
17
        Info = 0,
18
        Debug,
19
        Error
20
    }
21

  
22
    enum LogFlow {
23
        Console = 0,
24
        File
25
    }
26

  
27

  
28
    public abstract class Logger : IDisposable {
29

  
30
        private LogVerbosity _verbosity;
31
        private LogFlow _logFlow;
32

  
33
        private Queue<Action> _queue = new Queue<Action>();
34
        private ManualResetEvent _hasNewItems = new ManualResetEvent(false);
35
        private ManualResetEvent _terminate = new ManualResetEvent(false);
36
        private ManualResetEvent _waiting = new ManualResetEvent(false);
37
        private Thread _loggingThread;
38

  
39
        private static readonly Lazy<Logger> _lazyLog = new Lazy<Logger>(()
40
            => {
41
                switch (Program.Config.LogFlowType) {
42
                    case LogFlow.File:
43
                        return new FileLogger();
44
                    case LogFlow.Console:
45
                    default:
46
                        return new ConsoleLogger();
47

  
48
                }
49
            }
50
        );
51

  
52
        public static Logger Current => _lazyLog.Value;
53

  
54
        protected Logger() {
55
            _verbosity = (LogVerbosity)Program.Config.LogVerbosityType;
56
            _logFlow = (LogFlow)Program.Config.LogFlowType;
57
            _loggingThread = new Thread(new ThreadStart(ProcessQueue)) { IsBackground = true };
58
            _loggingThread.Start();
59
        }
60

  
61
        public void Info(string message) {
62
            Log(message, LogType.Info);
63
        }
64

  
65
        public void Debug(string message) {
66
            Log(message, LogType.Debug);
67
        }
68

  
69
        public void Error(string message) {
70
            Log(message, LogType.Error);
71
        }
72

  
73
        public void Error(Exception e) {
74
            if (_verbosity != LogVerbosity.None) {
75
                Log(UnwrapExceptionMessages(e), LogType.Error);
76
            }
77
        }
78

  
79
        public override string ToString() => $"Logger settings: [Type: {this.GetType().Name}, Verbosity: {_verbosity}, ";
80

  
81
        protected abstract void CreateLog(string message);
82

  
83
        public void Flush() => _waiting.WaitOne();
84

  
85
        public void Dispose() {
86
            _terminate.Set();
87
            _loggingThread.Join();
88
        }
89

  
90
        protected virtual string ComposeLogRow(string message, LogType logType) =>
91
            $"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff", CultureInfo.InvariantCulture)} - {logType}] - {message}";
92

  
93
        protected virtual string UnwrapExceptionMessages(Exception ex) {
94
            if (ex == null)
95
                return string.Empty;
96

  
97
            return $"{ex}, Inner exception: {UnwrapExceptionMessages(ex.InnerException)} ";
98
        }
99

  
100
        private void ProcessQueue() {
101
            while (true) {
102
                _waiting.Set();
103
                int i = WaitHandle.WaitAny(new WaitHandle[] { _hasNewItems, _terminate });
104
                if (i == 1) return;
105
                _hasNewItems.Reset();
106
                _waiting.Reset();
107

  
108
                Queue<Action> queueCopy;
109
                lock (_queue) {
110
                    queueCopy = new Queue<Action>(_queue);
111
                    _queue.Clear();
112
                }
113

  
114
                foreach (var log in queueCopy) {
115
                    log();
116
                }
117
            }
118
        }
119

  
120
        private void Log(string message, LogType logType) {
121
            if (string.IsNullOrEmpty(message))
122
                return;
123

  
124
            var logRow = ComposeLogRow(message, logType);
125
            System.Diagnostics.Debug.WriteLine(logRow);
126

  
127
            if (_verbosity == LogVerbosity.Full) {
128
                lock (_queue)
129
                    _queue.Enqueue(() => CreateLog(logRow));
130

  
131
                _hasNewItems.Set();
132
            }
133
        }
134
    }
135

  
136
    class ConsoleLogger : Logger {
137
        protected override void CreateLog(string message) {
138
            Console.WriteLine(message);
139
        }
140
    }
141

  
142

  
143
    class FileLogger : Logger {
144

  
145
        private const string LogFolderName = "logs";
146
        private const string LogFileName = "app_info.log";
147
        private readonly int _logChunkSize = Program.Config.LogChunkSize;
148
        private readonly int _logChunkMaxCount = Program.Config.LogChunkMaxCount;
149
        private readonly int _logArchiveMaxCount = Program.Config.LogArchiveMaxCount;
150
        private readonly int _logCleanupPeriod = Program.Config.LogCleanupPeriod;
151

  
152
        private readonly string logFolderPath = Path.Combine(Path.GetTempPath(), $"ldClient\\{LogFolderName}");
153

  
154
        private bool _logDirExists = false;
155

  
156
        protected override void CreateLog(string message) {
157

  
158
            if (!_logDirExists) {
159
                _logDirExists = Directory.Exists(logFolderPath);
160
                if (!_logDirExists) {
161
                    Directory.CreateDirectory(logFolderPath);
162
                    _logDirExists = true;
163
                }
164
            }
165

  
166
            var logFilePath = Path.Combine(logFolderPath, LogFileName);
167

  
168
            Rotate(logFilePath);
169

  
170
            using (var sw = File.AppendText(logFilePath)) {
171
                sw.WriteLine(message);
172
            }
173
        }
174

  
175
        private void Rotate(string filePath) {
176
            if (!File.Exists(filePath))
177
                return;
178

  
179
            var fileInfo = new FileInfo(filePath);
180
            if (fileInfo.Length < _logChunkSize)
181
                return;
182

  
183
            var fileTime = DateTime.Now.ToString("dd-MM-yyyy,hh-mm-ss,fff");
184
            var rotatedPath = filePath.Replace(".log", $".{fileTime}");
185
            File.Move(filePath, rotatedPath);
186

  
187
            var folderPath = Path.GetDirectoryName(rotatedPath);
188
            var logFolderContent = new DirectoryInfo(folderPath).GetFileSystemInfos();
189

  
190
            var chunks = logFolderContent.Where(x => !x.Extension.Equals(".zip", StringComparison.OrdinalIgnoreCase));
191

  
192
            if (chunks.Count() <= _logChunkMaxCount)
193
                return;
194

  
195
            var archiveFolderInfo = Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(rotatedPath), $"{LogFolderName}_{fileTime}"));
196

  
197
            foreach (var chunk in chunks) {
198
                var destination = Path.Combine(archiveFolderInfo.FullName, chunk.Name);
199
                Directory.Move(chunk.FullName, destination);
200
            }
201

  
202
            ZipFile.CreateFromDirectory(archiveFolderInfo.FullName, Path.Combine(folderPath, $"{LogFolderName}_{fileTime}.zip"));
203
            Directory.Delete(archiveFolderInfo.FullName, true);
204

  
205
            var archives = logFolderContent.Where(x => x.Extension.Equals(".zip", StringComparison.OrdinalIgnoreCase)).ToArray();
206

  
207
            if (archives.Count() <= _logArchiveMaxCount)
208
                return;
209

  
210
            var oldestArchive = archives.OrderBy(x => x.CreationTime).First();
211
            var cleanupDate = oldestArchive.CreationTime.AddDays(_logCleanupPeriod);
212
            if (DateTime.Compare(cleanupDate, DateTime.Now) <= 0) {
213
                foreach (var file in logFolderContent) {
214
                    file.Delete();
215
                }
216
            } else
217
                File.Delete(oldestArchive.FullName);
218

  
219
        }
220

  
221
        public override string ToString() => $"{base.ToString()}, Chunk Size: {_logChunkSize}, Max chunk count: {_logChunkMaxCount}, Max log archive count: {_logArchiveMaxCount}, Cleanup period: {_logCleanupPeriod} days]";
222
    }
223

  
224

  
225
}

Také k dispozici: Unified diff