AsyncLogTargetWrapper.cs 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Threading;
  4. namespace Ryujinx.Common.Logging
  5. {
  6. public enum AsyncLogTargetOverflowAction
  7. {
  8. /// <summary>
  9. /// Block until there's more room in the queue
  10. /// </summary>
  11. Block = 0,
  12. /// <summary>
  13. /// Discard the overflowing item
  14. /// </summary>
  15. Discard = 1
  16. }
  17. public class AsyncLogTargetWrapper : ILogTarget
  18. {
  19. private ILogTarget _target;
  20. private Thread _messageThread;
  21. private BlockingCollection<LogEventArgs> _messageQueue;
  22. private readonly int _overflowTimeout;
  23. string ILogTarget.Name { get => _target.Name; }
  24. public AsyncLogTargetWrapper(ILogTarget target)
  25. : this(target, -1, AsyncLogTargetOverflowAction.Block)
  26. { }
  27. public AsyncLogTargetWrapper(ILogTarget target, int queueLimit, AsyncLogTargetOverflowAction overflowAction)
  28. {
  29. _target = target;
  30. _messageQueue = new BlockingCollection<LogEventArgs>(queueLimit);
  31. _overflowTimeout = overflowAction == AsyncLogTargetOverflowAction.Block ? -1 : 0;
  32. _messageThread = new Thread(() => {
  33. while (!_messageQueue.IsCompleted)
  34. {
  35. try
  36. {
  37. _target.Log(this, _messageQueue.Take());
  38. }
  39. catch (InvalidOperationException)
  40. {
  41. // IOE means that Take() was called on a completed collection.
  42. // Some other thread can call CompleteAdding after we pass the
  43. // IsCompleted check but before we call Take.
  44. // We can simply catch the exception since the loop will break
  45. // on the next iteration.
  46. }
  47. }
  48. });
  49. _messageThread.Name = "Logger.MessageThread";
  50. _messageThread.IsBackground = true;
  51. _messageThread.Start();
  52. }
  53. public void Log(object sender, LogEventArgs e)
  54. {
  55. if (!_messageQueue.IsAddingCompleted)
  56. {
  57. _messageQueue.TryAdd(e, _overflowTimeout);
  58. }
  59. }
  60. public void Dispose()
  61. {
  62. _messageQueue.CompleteAdding();
  63. _messageThread.Join();
  64. }
  65. }
  66. }