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.

133 lines
4.1 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 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 GZipStream zstream;
  27. private FileStream fstream;
  28. /// <summary>
  29. /// Gets the <see cref="FileInfo"/> for the file to write to without the .gz extension.
  30. /// </summary>
  31. /// <returns></returns>
  32. protected abstract FileInfo GetFileInfo();
  33. private void InitLog()
  34. {
  35. try
  36. {
  37. if (fileInfo == null)
  38. { // first init
  39. fileInfo = GetFileInfo();
  40. var ext = fileInfo.Extension;
  41. fileInfo = new FileInfo(fileInfo.FullName + ".gz");
  42. fileInfo.Create().Close();
  43. var symlink = new FileInfo(Path.Combine(fileInfo.DirectoryName ?? throw new InvalidOperationException(), $"_latest{ext}.gz"));
  44. if (symlink.Exists) symlink.Delete();
  45. try
  46. {
  47. if (!CreateHardLink(symlink.FullName, fileInfo.FullName, IntPtr.Zero))
  48. {
  49. var error = Marshal.GetLastWin32Error();
  50. Logger.log.Error($"Hardlink creation failed ({error})");
  51. }
  52. }
  53. catch (Exception e)
  54. {
  55. Logger.log.Error("Error creating latest hardlink!");
  56. Logger.log.Error(e);
  57. }
  58. }
  59. }
  60. catch (Exception e)
  61. {
  62. Logger.log.Error("Error initializing log!");
  63. Logger.log.Error(e);
  64. }
  65. }
  66. /// <summary>
  67. /// Called at the start of any print session.
  68. /// </summary>
  69. public sealed override void StartPrint()
  70. {
  71. InitLog();
  72. fstream = fileInfo.Open(FileMode.Append, FileAccess.Write);
  73. zstream = new GZipStream(fstream, CompressionMode.Compress)
  74. {
  75. FlushMode = FlushType.Full
  76. };
  77. FileWriter = new StreamWriter(zstream, new UTF8Encoding(false));
  78. }
  79. /// <summary>
  80. /// Called at the end of any print session.
  81. /// </summary>
  82. public sealed override void EndPrint()
  83. {
  84. FileWriter.Flush();
  85. zstream.Flush();
  86. fstream.Flush();
  87. FileWriter.Dispose();
  88. zstream.Dispose();
  89. fstream.Dispose();
  90. FileWriter = null;
  91. zstream = null;
  92. fstream = null;
  93. }
  94. /// <inheritdoc />
  95. public void Dispose()
  96. {
  97. Dispose(true);
  98. GC.SuppressFinalize(this);
  99. }
  100. /// <summary>
  101. /// Disposes the file printer.
  102. /// </summary>
  103. /// <param name="disposing">does nothing</param>
  104. protected virtual void Dispose(bool disposing)
  105. {
  106. if (disposing)
  107. {
  108. FileWriter.Flush();
  109. zstream.Flush();
  110. fstream.Flush();
  111. FileWriter.Close();
  112. zstream.Close();
  113. fstream.Close();
  114. FileWriter.Dispose();
  115. zstream.Dispose();
  116. fstream.Dispose();
  117. }
  118. }
  119. }
  120. }