BusMessageLogger.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Reflection;
  5. using Abc.Zebus.Scan;
  6. using Abc.Zebus.Util.Annotations;
  7. using Abc.Zebus.Util.Extensions;
  8. using log4net;
  9. using log4net.Core;
  10. namespace Abc.Zebus.Core
  11. {
  12. public class BusMessageLogger
  13. {
  14. private static readonly ConcurrentDictionary<Type, MessageTypeLogInfo> _logInfos = new ConcurrentDictionary<Type, MessageTypeLogInfo>();
  15. private static readonly Func<Type, MessageTypeLogInfo> _logInfoFactory = CreateLogger;
  16. private readonly Type _loggerType;
  17. private readonly ILog _logger;
  18. private bool _logDebugEnabled;
  19. private bool _logInfoEnabled;
  20. public BusMessageLogger(Type loggerType)
  21. : this(loggerType, loggerType.FullName)
  22. {
  23. }
  24. public BusMessageLogger(Type loggerType, string loggerFullName)
  25. {
  26. _loggerType = loggerType;
  27. _logger = LogManager.GetLogger(typeof(BusMessageLogger).Assembly, loggerFullName);
  28. // Instances of BusMessageLogger are static, no need to unsubscribe from these events
  29. _logger.Logger.Repository.ConfigurationChanged += (sender, args) => UpdateLogConfig();
  30. _logger.Logger.Repository.ConfigurationReset += (sender, args) => UpdateLogConfig();
  31. UpdateLogConfig();
  32. void UpdateLogConfig()
  33. {
  34. _logDebugEnabled = _logger.IsDebugEnabled;
  35. _logInfoEnabled = _logger.IsInfoEnabled;
  36. }
  37. }
  38. public bool IsInfoEnabled(IMessage message)
  39. => _logInfoEnabled && GetLogInfo(message).Logger.IsInfoEnabled;
  40. [StringFormatMethod("format")]
  41. public void InfoFormat(string format, IMessage message, string dispatchQueueName = null, MessageId? messageId = null, long messageSize = 0, PeerId peerId = default(PeerId))
  42. {
  43. if (!_logInfoEnabled)
  44. return;
  45. var logInfo = GetLogInfo(message);
  46. if (!logInfo.Logger.IsInfoEnabled)
  47. return;
  48. var messageText = logInfo.GetMessageText(message);
  49. dispatchQueueName = string.IsNullOrEmpty(dispatchQueueName) || dispatchQueueName == DispatchQueueNameScanner.DefaultQueueName ? string.Empty : $" [{dispatchQueueName}]";
  50. _logger.InfoFormat(format, messageText, dispatchQueueName, messageId, messageSize, peerId);
  51. }
  52. [StringFormatMethod("format")]
  53. public void DebugFormat(string format, IMessage message, MessageId? messageId = null, long messageSize = 0, PeerId peerId = default(PeerId))
  54. {
  55. if (!_logDebugEnabled)
  56. return;
  57. var logInfo = GetLogInfo(message);
  58. if (!logInfo.Logger.IsDebugEnabled)
  59. return;
  60. var messageText = logInfo.GetMessageText(message);
  61. _logger.DebugFormat(format, messageText, messageId, messageSize, peerId);
  62. }
  63. [StringFormatMethod("format")]
  64. public void InfoFormat(string format, IMessage message, MessageId messageId, long messageSize, IList<Peer> peers, Level logLevel = null)
  65. {
  66. if (!_logInfoEnabled)
  67. return;
  68. switch (peers.Count)
  69. {
  70. case 0:
  71. InfoFormat(format, message, messageId: messageId, messageSize: messageSize);
  72. return;
  73. case 1:
  74. InfoFormat(format, message, messageId: messageId, messageSize:messageSize, peerId:peers[0].Id);
  75. return;
  76. }
  77. var logInfo = GetLogInfo(message);
  78. if (!logInfo.Logger.IsInfoEnabled)
  79. return;
  80. var messageText = logInfo.GetMessageText(message);
  81. var otherPeersCount = peers.Count - 1;
  82. var peerIdText = otherPeersCount > 1
  83. ? peers[0].Id + " and " + otherPeersCount + " other peers"
  84. : peers[0].Id + " and " + otherPeersCount + " other peer";
  85. _logger.Logger.Log(_loggerType, logLevel ?? Level.Info, string.Format(format, messageText, messageId, messageSize, peerIdText), null);
  86. }
  87. public static string ToString(IMessage message)
  88. => GetLogInfo(message).GetMessageText(message);
  89. private static MessageTypeLogInfo GetLogInfo(IMessage message)
  90. => _logInfos.GetOrAdd(message.GetType(), _logInfoFactory);
  91. private static MessageTypeLogInfo CreateLogger(Type messageType)
  92. {
  93. var logger = LogManager.GetLogger(messageType);
  94. var hasToStringOverride = HasToStringOverride(messageType);
  95. return new MessageTypeLogInfo(logger, hasToStringOverride, messageType.GetPrettyName());
  96. }
  97. private static bool HasToStringOverride(Type messageType)
  98. {
  99. var methodInfo = messageType.GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
  100. return methodInfo != null;
  101. }
  102. private class MessageTypeLogInfo
  103. {
  104. public readonly ILog Logger;
  105. private readonly bool _hasToStringOverride;
  106. private readonly string _messageTypeName;
  107. public MessageTypeLogInfo(ILog logger, bool hasToStringOverride, string messageTypeName)
  108. {
  109. Logger = logger;
  110. _hasToStringOverride = hasToStringOverride;
  111. _messageTypeName = messageTypeName;
  112. }
  113. public string GetMessageText(IMessage message)
  114. {
  115. return _hasToStringOverride ? $"{_messageTypeName} {{{message}}}" : $"{_messageTypeName}";
  116. }
  117. }
  118. }
  119. }