1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //------------------------------------------------------------
5 namespace System.ServiceModel.Diagnostics
7 using System.Collections.Generic;
8 using System.Diagnostics;
11 using System.Runtime.Diagnostics;
12 using System.Security;
13 using System.ServiceModel;
14 using System.ServiceModel.Channels;
15 using System.ServiceModel.Configuration;
16 using System.ServiceModel.Diagnostics.Application;
17 using System.ServiceModel.Dispatcher;
21 internal enum MessageLoggingSource : int
26 Transport = TransportReceive | TransportSend,
27 ServiceLevelReceiveDatagram = 16,
28 ServiceLevelSendDatagram = 32,
29 ServiceLevelReceiveRequest = 64,
30 ServiceLevelSendRequest = 128,
31 ServiceLevelReceiveReply = 256,
32 ServiceLevelSendReply = 512,
33 ServiceLevelReceive = ServiceLevelReceiveReply | ServiceLevelReceiveRequest | ServiceLevelReceiveDatagram,
34 ServiceLevelSend = ServiceLevelSendReply | ServiceLevelSendRequest | ServiceLevelSendDatagram,
35 ServiceLevelService = ServiceLevelSendReply | ServiceLevelReceiveRequest | ServiceLevelReceiveDatagram,
36 ServiceLevelProxy = ServiceLevelReceiveReply | ServiceLevelSendRequest | ServiceLevelSendDatagram,
37 ServiceLevel = ServiceLevelReceive | ServiceLevelSend,
43 internal static class MessageLogger
45 const string MessageTraceSourceName = "System.ServiceModel.MessageLogging";
46 const string DefaultTraceListenerName = "Default";
47 const int Unlimited = -1;
49 static MessageLoggingSource sources = default(MessageLoggingSource);
50 static bool logKnownPii;
51 static bool logMessageBody = false;
52 static int maxMessagesToLog;
53 static int numberOfMessagesToLog;
54 static int maxMessageSize;
55 static PiiTraceSource messageTraceSource;
56 static bool attemptedTraceSourceInitialization = false;
57 static bool initialized = false;
58 static bool initializing = false;
59 static bool inPartialTrust = false;
60 static object syncObject = new object();
61 static object filterLock = new object();
62 static List<XPathMessageFilter> messageFilterTable;
63 static bool lastWriteSucceeded = true;
64 static string[][] piiBodyPaths;
65 static string[][] piiHeadersPaths;
66 static string[] securityActions;
68 static int FilterCount
70 get { return MessageLogger.Filters.Count; }
73 static bool FilterMessages
75 get { return MessageLogger.FilterCount > 0 && (MessageLogger.numberOfMessagesToLog > 0 || MessageLogger.numberOfMessagesToLog == MessageLogger.Unlimited); }
78 internal static bool LogKnownPii
82 Fx.Assert(MessageLogger.initialized, "MessageLogger should be initialized before trying to retrieve LogKnownPii");
83 return MessageLogger.logKnownPii;
87 MessageLogger.logKnownPii = value;
91 internal static bool LogMalformedMessages
93 get { return (MessageLogger.Sources & MessageLoggingSource.Malformed) != 0; }
96 lock (MessageLogger.syncObject)
98 bool shouldProcessAudit = ShouldProcessAudit(MessageLoggingSource.Malformed, value);
101 EnsureMessageTraceSource();
102 if (!MessageLogger.inPartialTrust)
104 MessageLogger.sources |= MessageLoggingSource.Malformed;
109 MessageLogger.sources &= MessageLoggingSource.All & ~MessageLoggingSource.Malformed;
111 if (shouldProcessAudit)
119 internal static bool LogMessagesAtServiceLevel
121 get { return (MessageLogger.Sources & MessageLoggingSource.ServiceLevel) != 0; }
124 lock (MessageLogger.syncObject)
126 bool shouldProcessAudit = ShouldProcessAudit(MessageLoggingSource.ServiceLevel, value);
129 EnsureMessageTraceSource();
130 if (!MessageLogger.inPartialTrust)
132 MessageLogger.sources |= MessageLoggingSource.ServiceLevel;
137 MessageLogger.sources &= MessageLoggingSource.All & ~MessageLoggingSource.ServiceLevel;
139 if (shouldProcessAudit)
147 internal static bool LogMessagesAtTransportLevel
149 get { return (MessageLogger.Sources & MessageLoggingSource.Transport) != 0; }
152 lock (MessageLogger.syncObject)
154 bool shouldProcessAudit = ShouldProcessAudit(MessageLoggingSource.Transport, value);
157 EnsureMessageTraceSource();
158 if (!MessageLogger.inPartialTrust)
160 MessageLogger.sources |= MessageLoggingSource.Transport;
165 MessageLogger.sources &= MessageLoggingSource.All & ~MessageLoggingSource.Transport;
167 if (shouldProcessAudit)
175 internal static bool LogMessageBody
179 Fx.Assert(MessageLogger.initialized, "");
180 return logMessageBody;
182 set { logMessageBody = value; }
185 internal static bool LoggingEnabled
187 get { return MessageLogger.Sources != default(MessageLoggingSource); }
190 internal static int MaxMessageSize
194 Fx.Assert(MessageLogger.initialized, "");
195 return maxMessageSize;
197 set { maxMessageSize = value; }
200 internal static int MaxNumberOfMessagesToLog
204 Fx.Assert(MessageLogger.initialized, "");
205 return maxMessagesToLog;
209 //resetting the max resets the actual counter
210 lock (MessageLogger.syncObject)
212 maxMessagesToLog = value;
213 MessageLogger.numberOfMessagesToLog = maxMessagesToLog;
218 static List<XPathMessageFilter> Filters
222 if (MessageLogger.messageFilterTable == null)
224 lock (MessageLogger.filterLock)
226 if (MessageLogger.messageFilterTable == null)
228 List<XPathMessageFilter> temp = new List<XPathMessageFilter>();
229 MessageLogger.messageFilterTable = temp;
234 return MessageLogger.messageFilterTable;
238 static MessageLoggingSource Sources
242 if (!MessageLogger.initialized)
244 MessageLogger.EnsureInitialized();
246 return MessageLogger.sources;
250 static bool AddFilter(XPathMessageFilter filter)
254 filter = new XPathMessageFilter(""); //if there is an empty add filter tag, add a match-all filter
257 MessageLogger.Filters.Add(filter);
261 internal static bool ShouldLogMalformed
263 get { return ShouldLogMessages(MessageLoggingSource.Malformed); }
266 static bool ShouldLogMessages(MessageLoggingSource source)
268 return (source & MessageLogger.Sources) != 0 &&
269 ((MessageLogger.MessageTraceSource != null) ||
270 ((source & MessageLoggingSource.Malformed) != 0 && TD.MessageLogWarningIsEnabled()) ||
271 TD.MessageLogInfoIsEnabled());
274 internal static void LogMessage(MessageLoggingSource source, string data)
278 if (ShouldLogMessages(MessageLoggingSource.Malformed))
280 LogInternal(source, data);
283 #pragma warning suppress 56500 // covered by FxCOP
286 if (Fx.IsFatal(e)) throw;
287 FailedToLogMessage(e);
291 internal static void LogMessage(Stream stream, MessageLoggingSource source)
295 ThrowIfNotMalformed(source);
296 if (ShouldLogMessages(source))
298 LogInternal(new MessageLogTraceRecord(stream, source));
301 #pragma warning suppress 56500 // covered by FxCOP
304 if (Fx.IsFatal(e)) throw;
305 FailedToLogMessage(e);
309 internal static void LogMessage(ArraySegment<byte> buffer, MessageLoggingSource source)
313 ThrowIfNotMalformed(source);
314 if (ShouldLogMessages(source))
316 LogInternal(new MessageLogTraceRecord(buffer, source));
319 #pragma warning suppress 56500 // covered by FxCOP
322 if (Fx.IsFatal(e)) throw;
323 FailedToLogMessage(e);
327 internal static void LogMessage(ref Message message, XmlReader reader, MessageLoggingSource source)
329 Fx.Assert(null != message, "");
332 if (ShouldLogMessages(source))
334 LogMessageImpl(ref message, reader, source);
337 #pragma warning suppress 56500 // covered by FxCOP
340 if (Fx.IsFatal(e)) throw;
341 FailedToLogMessage(e);
345 internal static void LogMessage(ref Message message, MessageLoggingSource source)
347 LogMessage(ref message, null, source);
350 static void LogMessageImpl(ref Message message, XmlReader reader, MessageLoggingSource source)
352 ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? TraceUtility.ExtractActivity(message) : null;
353 using (ServiceModelActivity.BoundOperation(activity))
355 if (ShouldLogMessages(source) && (MessageLogger.numberOfMessagesToLog > 0 || MessageLogger.numberOfMessagesToLog == MessageLogger.Unlimited))
357 bool lastChance = (source & MessageLoggingSource.LastChance) != 0 || (source & MessageLoggingSource.TransportSend) != 0;
358 source &= ~MessageLoggingSource.LastChance;
359 // MessageLogger doesn't log AddressingVersion.None in the encoder since we want to make sure we log
360 // as much of the message as possible. So let the Transport log later.
361 if ((lastChance || message is NullMessage || message.Version.Addressing != AddressingVersion.None)
362 && MatchFilters(message, source))
364 if (MessageLogger.numberOfMessagesToLog == MessageLogger.Unlimited || MessageLogger.numberOfMessagesToLog > 0)
366 MessageLogTraceRecord record = new MessageLogTraceRecord(ref message, reader, source, MessageLogger.LogMessageBody);
374 static bool HasSecurityAction(Message message)
376 Fx.Assert(null != message, "");
378 string action = message.Headers.Action;
380 if (String.IsNullOrEmpty(action))
386 foreach (string securityAction in MessageLogger.SecurityActions)
388 if (0 == String.CompareOrdinal(action, securityAction))
399 static void LogInternal(MessageLogTraceRecord record)
401 Fx.Assert(null != record, "record cannot be null");
403 PlainXmlWriter xmlWriter = new PlainXmlWriter(MessageLogger.MaxMessageSize);
407 record.WriteTo(xmlWriter);
409 TraceXPathNavigator navigator = xmlWriter.Navigator;
411 if ((MessageLogger.messageTraceSource != null &&
412 !MessageLogger.messageTraceSource.ShouldLogPii) ||
413 !MessageLogger.LogKnownPii)
415 navigator.RemovePii(MessageLogger.PiiHeadersPaths);
416 if (MessageLogger.LogMessageBody && null != record.Message)
418 if (HasSecurityAction(record.Message))
420 navigator.RemovePii(MessageLogger.PiiBodyPaths);
425 LogInternal(record.MessageLoggingSource, navigator);
427 catch (PlainXmlWriter.MaxSizeExceededException)
429 if (DiagnosticUtility.ShouldTraceWarning)
431 TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.MessageNotLoggedQuotaExceeded,
432 SR.GetString(SR.TraceCodeMessageNotLoggedQuotaExceeded), record.Message);
437 static void IncrementLoggedMessagesCount(object data)
439 if (MessageLogger.numberOfMessagesToLog > 0)
441 lock (MessageLogger.syncObject)
443 if (MessageLogger.numberOfMessagesToLog > 0)
445 MessageLogger.numberOfMessagesToLog--;
446 if (0 == MessageLogger.numberOfMessagesToLog)
448 if (DiagnosticUtility.ShouldTraceInformation)
450 TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.MessageCountLimitExceeded,
451 SR.GetString(SR.TraceCodeMessageCountLimitExceeded), data);
458 lock (MessageLogger.syncObject)
460 if (!MessageLogger.lastWriteSucceeded)
462 MessageLogger.lastWriteSucceeded = true;
467 static void FailedToLogMessage(Exception e)
469 //If something goes wrong, we do not want to fail the app, just log one event log entry per block of failures
470 bool shouldLogError = false;
471 lock (MessageLogger.syncObject)
473 if (MessageLogger.lastWriteSucceeded)
475 MessageLogger.lastWriteSucceeded = false;
476 shouldLogError = true;
481 DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
482 (ushort)System.Runtime.Diagnostics.EventLogCategory.MessageLogging,
483 (uint)System.Runtime.Diagnostics.EventLogEventId.FailedToLogMessage,
488 static void LogInternal(MessageLoggingSource source, object data)
490 if ((source & MessageLoggingSource.Malformed) != 0)
492 if (!TD.MessageLogWarning(data.ToString()))
494 if (TD.MessageLogEventSizeExceededIsEnabled())
496 TD.MessageLogEventSizeExceeded();
502 if (!TD.MessageLogInfo(data.ToString()))
504 if (TD.MessageLogEventSizeExceededIsEnabled())
506 TD.MessageLogEventSizeExceeded();
510 if (MessageLogger.MessageTraceSource != null)
512 MessageLogger.MessageTraceSource.TraceData(TraceEventType.Information, 0, data);
514 IncrementLoggedMessagesCount(data);
517 static bool MatchFilters(Message message, MessageLoggingSource source)
520 if (MessageLogger.FilterMessages && (source & MessageLoggingSource.Malformed) == 0)
523 List<XPathMessageFilter> filtersToRemove = new List<XPathMessageFilter>();
524 lock (MessageLogger.syncObject)
526 foreach (XPathMessageFilter filter in MessageLogger.Filters)
530 if (filter.Match(message))
536 catch (FilterInvalidBodyAccessException)
538 filtersToRemove.Add(filter);
540 catch (MessageFilterException e)
542 if (DiagnosticUtility.ShouldTraceInformation)
544 TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.FilterNotMatchedNodeQuotaExceeded,
545 SR.GetString(SR.TraceCodeFilterNotMatchedNodeQuotaExceeded), e, message);
550 foreach (XPathMessageFilter filter in filtersToRemove)
552 MessageLogger.Filters.Remove(filter);
553 PlainXmlWriter writer = new PlainXmlWriter();
554 filter.WriteXPathTo(writer, null, ConfigurationStrings.Filter, null, true);
555 DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
556 (ushort)System.Runtime.Diagnostics.EventLogCategory.MessageLogging,
557 (uint)System.Runtime.Diagnostics.EventLogEventId.RemovedBadFilter,
558 writer.Navigator.ToString());
561 if (MessageLogger.FilterCount == 0)
571 static void ReadFiltersFromConfig(DiagnosticSection section)
573 for (int i = 0; i < section.MessageLogging.Filters.Count; i++)
575 XPathMessageFilterElement xfe = section.MessageLogging.Filters[i];
576 AddFilter(xfe.Filter);
580 internal static TraceSource MessageTraceSource
584 return MessageLogger.messageTraceSource;
588 internal static void EnsureInitialized()
590 lock (MessageLogger.syncObject)
592 if (!MessageLogger.initialized && !MessageLogger.initializing)
598 #pragma warning suppress 56500 // covered by FxCOP
599 catch (SecurityException securityException)
601 // message logging is not support in PT, write the trace
602 MessageLogger.inPartialTrust = true;
603 if (DiagnosticUtility.ShouldTraceWarning)
605 TraceUtility.TraceEvent(TraceEventType.Warning,
606 TraceCode.TraceHandledException,
607 SR.GetString(SR.PartialTrustMessageLoggingNotEnabled),
611 // also write to event log
612 LogNonFatalInitializationException(
613 new SecurityException(
614 SR.GetString(SR.PartialTrustMessageLoggingNotEnabled),
618 MessageLogger.initialized = true;
623 static void EnsureMessageTraceSource()
625 if (!MessageLogger.initialized)
627 MessageLogger.EnsureInitialized();
629 if (null == MessageLogger.MessageTraceSource && !MessageLogger.attemptedTraceSourceInitialization)
631 InitializeMessageTraceSource();
635 static string[][] PiiBodyPaths
639 if (piiBodyPaths == null)
640 piiBodyPaths = new string[][] {
641 new string[] { MessageLogTraceRecord.MessageLogTraceRecordElementName, "Envelope", "Body", "RequestSecurityToken" },
642 new string[] { MessageLogTraceRecord.MessageLogTraceRecordElementName, "Envelope", "Body", "RequestSecurityTokenResponse" },
643 new string[] { MessageLogTraceRecord.MessageLogTraceRecordElementName, "Envelope", "Body", "RequestSecurityTokenResponseCollection" }
649 static string[][] PiiHeadersPaths
653 if (piiHeadersPaths == null)
654 piiHeadersPaths = new string[][] {
655 new string[] { MessageLogTraceRecord.MessageLogTraceRecordElementName, "Envelope", "Header", "Security" },
656 new string[] { MessageLogTraceRecord.MessageLogTraceRecordElementName, "Envelope", "Header", "IssuedTokens" }
658 return piiHeadersPaths;
662 static string[] SecurityActions
666 if (securityActions == null)
667 securityActions = new string[] {
668 "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue",
669 "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue",
670 "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Renew",
671 "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Renew",
672 "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Cancel",
673 "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Cancel",
674 "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Validate",
675 "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Validate",
676 "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT",
677 "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/SCT",
678 "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT/Amend",
679 "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/SCT/Amend",
680 "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT/Renew",
681 "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/SCT/Renew",
682 "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT/Cancel",
683 "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/SCT/Cancel",
684 "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/KET",
685 "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/KET",
686 "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RST/SCT",
687 "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RSTR/SCT",
688 "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RST/SCT-Amend",
689 "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RSTR/SCT-Amend",
690 "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RST/Issue",
691 "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RSTR/Issue",
692 "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RST/Renew",
693 "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RSTR/Renew",
694 "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RST/Validate",
695 "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RSTR/Validate",
696 "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RST/KET",
697 "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RSTR/KET"
699 return securityActions;
703 [Fx.Tag.SecurityNote(Critical = "Calls SecurityCritical method UnsafeGetSection which elevates in order to load config.",
704 Safe = "Does not leak any config objects.")]
705 [SecuritySafeCritical]
706 static void Initialize()
708 MessageLogger.initializing = true;
709 DiagnosticSection section = DiagnosticSection.UnsafeGetSection();
713 MessageLogger.LogKnownPii = section.MessageLogging.LogKnownPii && MachineSettingsSection.EnableLoggingKnownPii;
714 MessageLogger.LogMalformedMessages = section.MessageLogging.LogMalformedMessages;
715 MessageLogger.LogMessageBody = section.MessageLogging.LogEntireMessage;
716 MessageLogger.LogMessagesAtServiceLevel = section.MessageLogging.LogMessagesAtServiceLevel;
717 MessageLogger.LogMessagesAtTransportLevel = section.MessageLogging.LogMessagesAtTransportLevel;
718 MessageLogger.MaxNumberOfMessagesToLog = section.MessageLogging.MaxMessagesToLog;
719 MessageLogger.MaxMessageSize = section.MessageLogging.MaxSizeOfMessageToLog;
721 ReadFiltersFromConfig(section);
725 static void InitializeMessageTraceSource()
729 MessageLogger.attemptedTraceSourceInitialization = true;
730 PiiTraceSource tempSource = new PiiTraceSource(MessageLogger.MessageTraceSourceName, DiagnosticUtility.EventSourceName);
731 tempSource.Switch.Level = SourceLevels.Information;
732 tempSource.Listeners.Remove(MessageLogger.DefaultTraceListenerName);
733 if (tempSource.Listeners.Count > 0)
735 AppDomain.CurrentDomain.DomainUnload += new EventHandler(ExitOrUnloadEventHandler);
736 AppDomain.CurrentDomain.ProcessExit += new EventHandler(ExitOrUnloadEventHandler);
737 AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(ExitOrUnloadEventHandler);
744 MessageLogger.messageTraceSource = tempSource;
746 catch (System.Configuration.ConfigurationErrorsException)
750 #pragma warning suppress 56500 // covered by FxCOP
751 catch (SecurityException securityException)
753 // message logging is not support in PT, write the trace
754 MessageLogger.inPartialTrust = true;
755 if (DiagnosticUtility.ShouldTraceWarning)
757 TraceUtility.TraceEvent(TraceEventType.Warning,
758 TraceCode.TraceHandledException,
759 SR.GetString(SR.PartialTrustMessageLoggingNotEnabled),
763 // also write to event log
764 LogNonFatalInitializationException(
765 new SecurityException(
766 SR.GetString(SR.PartialTrustMessageLoggingNotEnabled),
771 MessageLogger.messageTraceSource = null;
773 if (Fx.IsFatal(e)) throw;
775 LogNonFatalInitializationException(e);
779 [Fx.Tag.SecurityNote(Critical = "Calls into an unsafe method to log event.",
780 Safe = "Event identities cannot be spoofed as they are constants determined inside the method.")]
781 [SecuritySafeCritical]
782 static void LogNonFatalInitializationException(Exception e)
784 DiagnosticUtility.UnsafeEventLog.UnsafeLogEvent(TraceEventType.Critical,
785 (ushort)System.Runtime.Diagnostics.EventLogCategory.MessageLogging,
786 (uint)System.Runtime.Diagnostics.EventLogEventId.FailedToCreateMessageLoggingTraceSource,
791 static void ExitOrUnloadEventHandler(object sender, EventArgs e)
793 lock (MessageLogger.syncObject)
795 if (null != MessageLogger.MessageTraceSource)
797 //Flush is called automatically on close by StreamWriter
798 MessageLogger.MessageTraceSource.Close();
799 MessageLogger.messageTraceSource = null;
804 static void ThrowIfNotMalformed(MessageLoggingSource source)
806 if ((source & MessageLoggingSource.Malformed) == 0)
808 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.OnlyMalformedMessagesAreSupported), "source"));
812 static void ProcessAudit(bool turningOn)
816 if (null != MessageLogger.messageTraceSource)
818 DiagnosticUtility.EventLog.LogEvent(TraceEventType.Information,
819 (ushort)System.Runtime.Diagnostics.EventLogCategory.MessageLogging,
820 (uint)System.Runtime.Diagnostics.EventLogEventId.MessageLoggingOn);
825 DiagnosticUtility.EventLog.LogEvent(TraceEventType.Information,
826 (ushort)System.Runtime.Diagnostics.EventLogCategory.MessageLogging,
827 (uint)System.Runtime.Diagnostics.EventLogEventId.MessageLoggingOff);
831 static bool ShouldProcessAudit(MessageLoggingSource source, bool turningOn)
836 result = MessageLogger.sources == MessageLoggingSource.None;
840 result = MessageLogger.sources == source;