You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

146 lines
4.6 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. using Ionic.Zlib;
  2. using System;
  3. using System.IO;
  4. using System.Runtime.InteropServices;
  5. using System.Text;
  6. using System.Text.RegularExpressions;
  7. namespace IPA.Logging.Printers
  8. {
  9. /// <summary>
  10. /// A <see cref="LogPrinter"/> abstract class that provides the utilities to write to a GZip file.
  11. /// </summary>
  12. public abstract class GZFilePrinter : LogPrinter, IDisposable
  13. {
  14. [DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
  15. private static extern bool CreateHardLink(
  16. string lpFileName,
  17. string lpExistingFileName,
  18. IntPtr lpSecurityAttributes
  19. );
  20. internal static Regex removeControlCodes = new Regex("\x1b\\[\\d+m", RegexOptions.Compiled);
  21. private FileInfo fileInfo;
  22. /// <summary>
  23. /// The <see cref="StreamWriter"/> that writes to the GZip file.
  24. /// </summary>
  25. protected StreamWriter FileWriter;
  26. private FileStream fstream;
  27. /// <summary>
  28. /// Gets the <see cref="FileInfo"/> for the file to write to without the .gz extension.
  29. /// </summary>
  30. /// <returns></returns>
  31. protected abstract FileInfo GetFileInfo();
  32. private const string latestFormat = "_latest{0}";
  33. private void InitLog()
  34. {
  35. try
  36. {
  37. if (fileInfo == null)
  38. { // first init
  39. fileInfo = GetFileInfo();
  40. var ext = fileInfo.Extension;
  41. var symlink = new FileInfo(Path.Combine(fileInfo.DirectoryName ?? throw new InvalidOperationException(), string.Format(latestFormat, ext)));
  42. if (symlink.Exists) symlink.Delete();
  43. foreach (var file in fileInfo.Directory.EnumerateFiles("*.log", SearchOption.TopDirectoryOnly))
  44. {
  45. if (file.Equals(fileInfo)) continue;
  46. if (file.Extension == ".gz") continue;
  47. CompressOldLog(file);
  48. }
  49. fileInfo.Create().Close();
  50. try
  51. {
  52. if (!CreateHardLink(symlink.FullName, fileInfo.FullName, IntPtr.Zero))
  53. {
  54. var error = Marshal.GetLastWin32Error();
  55. Logger.log.Error($"Hardlink creation failed ({error})");
  56. }
  57. }
  58. catch (Exception e)
  59. {
  60. Logger.log.Error("Error creating latest hardlink!");
  61. Logger.log.Error(e);
  62. }
  63. }
  64. }
  65. catch (Exception e)
  66. {
  67. Logger.log.Error("Error initializing log!");
  68. Logger.log.Error(e);
  69. }
  70. }
  71. private static async void CompressOldLog(FileInfo file)
  72. {
  73. Logger.log.Debug($"Compressing log file {file}");
  74. var newFile = new FileInfo(file.FullName + ".gz");
  75. using (var istream = file.OpenRead())
  76. using (var ostream = newFile.Create())
  77. using (var gz = new GZipStream(ostream, CompressionMode.Compress, CompressionLevel.BestCompression, false))
  78. await istream.CopyToAsync(gz);
  79. file.Delete();
  80. }
  81. /// <summary>
  82. /// Called at the start of any print session.
  83. /// </summary>
  84. public sealed override void StartPrint()
  85. {
  86. InitLog();
  87. fstream = fileInfo.Open(FileMode.Append, FileAccess.Write);
  88. FileWriter = new StreamWriter(fstream, new UTF8Encoding(false));
  89. }
  90. /// <summary>
  91. /// Called at the end of any print session.
  92. /// </summary>
  93. public sealed override void EndPrint()
  94. {
  95. FileWriter.Flush();
  96. fstream.Flush();
  97. FileWriter.Dispose();
  98. fstream.Dispose();
  99. FileWriter = null;
  100. fstream = null;
  101. }
  102. /// <inheritdoc />
  103. public void Dispose()
  104. {
  105. Dispose(true);
  106. GC.SuppressFinalize(this);
  107. }
  108. /// <summary>
  109. /// Disposes the file printer.
  110. /// </summary>
  111. /// <param name="disposing">does nothing</param>
  112. protected virtual void Dispose(bool disposing)
  113. {
  114. if (disposing)
  115. {
  116. FileWriter.Flush();
  117. fstream.Flush();
  118. FileWriter.Close();
  119. fstream.Close();
  120. FileWriter.Dispose();
  121. fstream.Dispose();
  122. }
  123. }
  124. }
  125. }