//****************************************************************************************************** // LogPublisher.cs - Gbtc // // Copyright © 2016, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/eclipse-1.0.php // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 10/24/2016 - Steven E. Chisholm // Generated original version of source code. // // //****************************************************************************************************** using System; using System.Collections.Concurrent; // ReSharper disable InconsistentlySynchronizedField namespace GSF.Diagnostics { /// /// A publisher of log messages. /// /// /// and can be modified so messages that are generated /// with this instance will have this data appended to the log message. /// /// The user can either call one of the Publish overloads to lazily publish a message, or they /// can register a message with RegisterEvent so calling this message will incur little overhead. /// If registering an event, the user can check to determine if the log message can be skipped altogether. /// Registering events also allows the user to specify the auto-suppression algorithm and the depth of the stack trace that will be recorded on a message being raised. /// /// public class LogPublisher { /// /// Occurs when a new is ready to be published. /// private LoggerInternal m_logger; private readonly LogPublisherInternal m_publisherInstance; private readonly MessageClass m_classification; /// /// The stack messages that existed when this publisher was created. This can be modified by the user of this publisher. /// Any messages that get published by this class will automatically have this data added to the log message. /// public LogStackMessages InitialStackMessages; /// /// The stack trace that existed when this publisher was created. This can be modified by the user of this publisher. /// Any messages that get published by this class will automatically have this data added to the log message. /// public LogStackTrace InitialStackTrace; /// /// The maximum number of distinct events that this publisher can generate. (Default: 20) /// /// /// Since message suppression and collection occurs at the event name level, it is important /// to have only a few distinct message types. This is the limit so misapplication /// of this publisher will not cause memory impacts on the system. /// /// It is recommended to keep the event name as a fixed string and not report any other meta data /// with the event. /// // ReSharper disable once ConvertToConstant.Global public int MaxDistinctEventPublisherCount { get; set; } /// /// Where the s of specific events are cached. /// private readonly ConcurrentDictionary, LogEventPublisherInternal> m_lookupEventPublishers; private LogEventPublisherInternal m_excessivePublisherEventNames; internal LogPublisher(LoggerInternal logger, LogPublisherInternal publisherInstance, MessageClass classification) { m_logger = logger; m_publisherInstance = publisherInstance; m_classification = classification; InitialStackMessages = Logger.GetStackMessages(); InitialStackTrace = new LogStackTrace(true, 1, 10); MaxDistinctEventPublisherCount = 20; m_lookupEventPublishers = new ConcurrentDictionary, LogEventPublisherInternal>(); } /// /// Initializes an with the provided values. /// /// the level of the message and associated flags if any /// the name of the event. /// public LogEventPublisher RegisterEvent(MessageLevel level, string eventName) { LogMessageAttributes flag = new LogMessageAttributes(m_classification, level, MessageSuppression.None, MessageFlags.None); LogEventPublisherInternal publisher = InternalRegisterEvent(flag, eventName); return new LogEventPublisher(this, publisher); } /// /// Initializes an with the provided values. /// /// the level of the message /// associated flags /// the name of the event. /// public LogEventPublisher RegisterEvent(MessageLevel level, MessageFlags flags, string eventName) { LogMessageAttributes flag = new LogMessageAttributes(m_classification, level, MessageSuppression.None, flags); LogEventPublisherInternal publisher = InternalRegisterEvent(flag, eventName); return new LogEventPublisher(this, publisher); } /// /// Initializes an with the provided values. /// /// the level of the message /// /// /// /// /// public LogEventPublisher RegisterEvent(MessageLevel level, string eventName, int stackTraceDepth, MessageRate messagesPerSecond, int burstLimit) { LogMessageAttributes flag = new LogMessageAttributes(m_classification, level, MessageSuppression.None, MessageFlags.None); LogEventPublisherInternal publisher = InternalRegisterEvent(flag, eventName, stackTraceDepth, messagesPerSecond, burstLimit); return new LogEventPublisher(this, publisher); } /// /// Initializes an with the provided values. /// /// the level of the message /// associated flags /// /// /// /// /// public LogEventPublisher RegisterEvent(MessageLevel level, MessageFlags flags, string eventName, int stackTraceDepth, MessageRate messagesPerSecond, int burstLimit) { LogMessageAttributes flag = new LogMessageAttributes(m_classification, level, MessageSuppression.None, flags); LogEventPublisherInternal publisher = InternalRegisterEvent(flag, eventName, stackTraceDepth, messagesPerSecond, burstLimit); return new LogEventPublisher(this, publisher); } /// /// Gets the full name of the type. /// /// public override string ToString() { return m_publisherInstance.TypeData.TypeName + " (" + m_publisherInstance.TypeData.AssemblyName + ")"; } /// /// Raises a log message with the provided data. /// /// the level of the message /// A short name about what this message is detailing. Typically this will be a few words. /// A longer message than giving more specifics about the actual message. /// Typically, this will be up to 1 line of text. /// A long text field with the details of the message. /// An exception object if one is provided. public void Publish(MessageLevel level, string eventName, string message = null, string details = null, Exception exception = null) { LogMessageAttributes flag = new LogMessageAttributes(m_classification, level, MessageSuppression.None, MessageFlags.None); InternalRegisterEvent(flag, eventName).Publish(null, message, details, exception, InitialStackMessages, InitialStackTrace); } /// /// Raises a log message with the provided data. /// /// the level of the message /// associated flags /// A short name about what this message is detailing. Typically this will be a few words. /// A longer message than giving more specifics about the actual message. /// Typically, this will be up to 1 line of text. /// A long text field with the details of the message. /// An exception object if one is provided. public void Publish(MessageLevel level, MessageFlags flags, string eventName, string message = null, string details = null, Exception exception = null) { LogMessageAttributes flag = new LogMessageAttributes(m_classification, level, MessageSuppression.None, flags); InternalRegisterEvent(flag, eventName).Publish(null, message, details, exception, InitialStackMessages, InitialStackTrace); } /// /// Initializes an with a series of settings. /// /// /// the name of the event. /// private LogEventPublisherInternal InternalRegisterEvent(LogMessageAttributes attributes, string eventName) { if (eventName == null) eventName = string.Empty; LogEventPublisherInternal publisher; if (m_lookupEventPublishers.TryGetValue(Tuple.Create(attributes, eventName), out publisher)) { return publisher; } //If messages events are unclassified allow a higher message throughput rate. double messagesPerSecond = 1; int burstRate = 20; if (eventName.Length == 0) { messagesPerSecond = 5; burstRate = 100; } return InternalRegisterNewEvent(attributes, eventName, 0, messagesPerSecond, burstRate); } /// /// Initializes an with a series of settings. /// /// /// /// /// /// /// private LogEventPublisherInternal InternalRegisterEvent(LogMessageAttributes attributes, string eventName, int stackTraceDepth, MessageRate messagesPerSecond, int burstLimit) { if (eventName == null) eventName = string.Empty; LogEventPublisherInternal publisher; if (m_lookupEventPublishers.TryGetValue(Tuple.Create(attributes, eventName), out publisher)) { return publisher; } return InternalRegisterNewEvent(attributes, eventName, stackTraceDepth, messagesPerSecond, burstLimit); } private LogEventPublisherInternal InternalRegisterNewEvent(LogMessageAttributes attributes, string eventName, int stackTraceDepth, double messagesPerSecond, int burstLimit) { //Note: A race condition can cause more then the maximum number of entries to exist, however, this is not a concern. if (m_lookupEventPublishers.Count > MaxDistinctEventPublisherCount) { if (m_excessivePublisherEventNames == null) { var owner1 = new LogEventPublisherDetails(m_publisherInstance.TypeData, "Excessive Event Names: Event names for this publisher has been limited to " + MaxDistinctEventPublisherCount.ToString() + "Please adjust MaxDistinctEventPublisherCount if this is not a bug and this publisher can truly create this many publishers."); m_excessivePublisherEventNames = new LogEventPublisherInternal(attributes, owner1, m_publisherInstance, m_logger, stackTraceDepth, messagesPerSecond, burstLimit); } return m_excessivePublisherEventNames; } LogEventPublisherInternal publisher; var owner = new LogEventPublisherDetails(m_publisherInstance.TypeData, eventName); publisher = new LogEventPublisherInternal(attributes, owner, m_publisherInstance, m_logger, stackTraceDepth, messagesPerSecond, burstLimit); publisher = m_lookupEventPublishers.GetOrAdd(Tuple.Create(attributes, eventName), publisher); return publisher; } } }