Projekt

Obecné

Profil

Stáhnout (5.17 KB) Statistiky
| Větev: | Tag: | Revize:
1
using System.IO.Compression;
2

    
3
namespace LDClient.utils.loggers; 
4

    
5
public class FileLogger : ALogger {
6

    
7
    /// <summary>
8
    /// Folder name for the created log files
9
    /// </summary>
10
    private const string LogFolderName = "logs";
11
    /// <summary>
12
    /// Base name of the log file
13
    /// </summary>
14
    private const string LogFileName = "app_info.log";
15
    
16
    private readonly int _logChunkSize = Program.Config.LogChunkSize;
17
    private readonly int _logChunkMaxCount = Program.Config.LogChunkMaxCount;
18
    private readonly int _logArchiveMaxCount = Program.Config.LogArchiveMaxCount;
19
    private readonly int _logCleanupPeriod = Program.Config.LogCleanupPeriod;
20

    
21
    /// <summary>
22
    /// Destination folder used to store the created logs and zipped chunks
23
    /// </summary>
24
    private const string LogFolderPath = $"ldClient\\{LogFolderName}";
25

    
26
    /// <summary>
27
    /// Flag that indicates that the log folder is already created
28
    /// </summary>
29
    private bool _logDirExists;
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>
38
    protected override void CreateLog(string message) {
39

    
40
        if (!_logDirExists) {
41
            _logDirExists = Directory.Exists(LogFolderPath);
42
            if (!_logDirExists) {
43
                Directory.CreateDirectory(LogFolderPath);
44
                _logDirExists = true;
45
            }
46
        }
47

    
48
        var logFilePath = Path.Combine(LogFolderPath, LogFileName);
49

    
50
        Rotate(logFilePath);
51

    
52
        using var sw = File.AppendText(logFilePath);
53
        sw.WriteLine(message);
54
    }
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>
60
    private void Rotate(string filePath) {
61
        if (!File.Exists(filePath)) {
62
            return;
63
        }
64

    
65
        var fileInfo = new FileInfo(filePath);
66
        if (fileInfo.Length < _logChunkSize) {
67
            return;
68
        }
69
        var fileTime = DateTime.Now.ToString("dd-MM-yyyy,hh-mm-ss,fff");
70
        var rotatedPath = filePath.Replace(".log", $".{fileTime}");
71
        File.Move(filePath, rotatedPath);
72

    
73
        var folderPath = Path.GetDirectoryName(rotatedPath);
74
        var logFolderContent = new DirectoryInfo(folderPath ?? string.Empty).GetFileSystemInfos();
75

    
76
        var chunks = logFolderContent.Where(x => 
77
            !x.Extension.Equals(".zip", StringComparison.OrdinalIgnoreCase));
78

    
79
        if (chunks.Count() <= _logChunkMaxCount) {
80
            return;
81
        }
82

    
83
        Archive(chunks, rotatedPath, fileTime, folderPath);
84
        DeleteOldArchives(logFolderContent);
85
    }
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>
94
    private void Archive(IEnumerable<FileSystemInfo> chunks, string rotatedPath, string fileTime, string? folderPath) {
95

    
96
        var archiveFolderInfo = Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(rotatedPath) ?? LogFolderPath, $"{LogFolderName}_{fileTime}"));
97

    
98
        foreach (var chunk in chunks) {
99
            var destination = Path.Combine(archiveFolderInfo.FullName, chunk.Name);
100
            Directory.Move(chunk.FullName, destination);
101
        }
102

    
103
        ZipFile.CreateFromDirectory(archiveFolderInfo.FullName, Path.Combine(folderPath ?? LogFolderPath, $"{LogFolderName}_{fileTime}.zip"));
104
        Directory.Delete(archiveFolderInfo.FullName, true);
105
    }
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>
112
    private void DeleteOldArchives(FileSystemInfo[] logFolderContent) {
113

    
114
        var archives = logFolderContent.Where(x => x.Extension.Equals(".zip", StringComparison.OrdinalIgnoreCase)).ToArray();
115
        
116
        if (archives.Length <= _logArchiveMaxCount)
117
            return;
118

    
119
        //find oldest archive in the folder
120
        var oldestArchive = archives.OrderBy(x => x.CreationTime).First();
121
        var cleanupDate = oldestArchive.CreationTime.AddDays(_logCleanupPeriod);
122
        //is there any file older than specified cleanup cleanup period
123
        if (DateTime.Compare(cleanupDate, DateTime.Now) <= 0) {
124
            foreach (var file in logFolderContent) {
125
                file.Delete();
126
            }
127
        } else {
128
            File.Delete(oldestArchive.FullName);
129
        }
130
    }
131
    public override string ToString() => $"{base.ToString()}, Chunk Size: {_logChunkSize}, Max chunk count: {_logChunkMaxCount}, Max log archive count: {_logArchiveMaxCount}, Cleanup period: {_logCleanupPeriod} days]";
132
}
(3-3/6)