using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net; using System.Net.Sockets; using System.Text; using Wayne.Lib.IO; namespace Wayne.Lib.Log { /// <summary> /// Logger is a static class used to create log objects. /// </summary> public static class Logger { #region Fields /// <summary> /// Default date and time format to use in log files. /// </summary> public const string DefaultDateTimeFormat = "HH':'mm':'ss'.'fff'[#]'"; private const int DefaultDebugMarkerBroadcastPort = 11001; private static readonly List<DebugLogger> OutstandingLogObjects = new List<DebugLogger>(); private static readonly object OutstandingLogObjectsLock = new object(); // Locking object to safely access the OutstandingLogObjects. private static readonly Dictionary<string, IEventSubscriber> EventSubscriberDict = new Dictionary<string, IEventSubscriber>(); private static readonly object EventSubscriberDictSyncObj = new object(); private static readonly Dictionary<string, ExternalLogWriter> ExternalLogWriterNameDict = new Dictionary<string, ExternalLogWriter>(); private static readonly Dictionary<ExternalLogWriterWrapper, ExternalLogWriter> ExternalLogWriterWrapperDict = new Dictionary<ExternalLogWriterWrapper, ExternalLogWriter>(); private static readonly object ExternalLogWriterDictSyncObj = new object(); private static readonly byte[] DebugMarkerBroadcastReceiverBuffer = new byte[100]; private static readonly List<string> DebugConfigFileNameList = new List<string>(); private static readonly List<string> EventConfigFileNameList = new List<string>(); private static readonly List<string[]> DebugConfigFilesList = new List<string[]>(); private static readonly List<string[]> EventConfigFilesList = new List<string[]>(); private static readonly List<LogConfigBuilder> DebugConfigBuilderList = new List<LogConfigBuilder>(); private static readonly List<LogConfigBuilder> EventConfigBuilderList = new List<LogConfigBuilder>(); private static readonly List<LogConfigOutput> LeftoverLinesLogConfigOutputs = new List<LogConfigOutput>(); private static readonly List<LogConfigOutput> LeftoverEntitiesLogConfigOutputs = new List<LogConfigOutput>(); private static bool active; private static LoggerThread loggerThread; private static LoggerThread eventLoggerThread; private static LogConfig debugConfig; private static LogConfig eventConfig; private static DotNetLog dotNetLog; private static GlobalLogEntryCounter globalLogEntryCounter; private static IPEndPoint debugMarkerBroadcastAddress; private static System.Net.Sockets.Socket debugMarkerBroadcastReceiverSocket; #endregion #region Construction static Logger() { Reset(); } #endregion #region Internal Properties /// <summary> /// Tells whether someone has called the Close() method. /// </summary> public static bool IsClosed { get { return !active; } } /// <summary> /// Internal access to the DebugConfig. /// </summary> internal static LogConfig DebugConfig { get { return debugConfig; } } /// <summary> /// Internal access to the GlobalLogEntryCounter. /// </summary> internal static GlobalLogEntryCounter GlobalLogEntryCounter { get { return globalLogEntryCounter; } } #endregion #region Internal Methods /// <summary> /// This method is used to fire an event instead of throwing an exception if something /// "crashes" in a thread (in order to keep the thread alive but still "report" exceptions). /// </summary> /// <param name="exception"></param> [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")] internal static void FireOnThreadException(LogException exception) { try { if (OnThreadException != null) OnThreadException(null, new EventArgs<LogException>(exception)); } catch (Exception) { } } /// <summary> /// Internal method that is used by the EventLogSubscriptionLogWriter to publish an /// event entry to a specific subscriber. /// </summary> /// <param name="eventSubscriberId"></param> /// <param name="eventLogEntry"></param> /// <param name="storageType"></param> internal static void PublishEventLog(string eventSubscriberId, EventLogEntry eventLogEntry, LogConfigEventLogStorageType storageType) { //eventLogStorage.Add(eventSubscriberId, eventLogEntry, storageType); IEventSubscriber eventSubscriber; lock (EventSubscriberDictSyncObj) { if (!EventSubscriberDict.TryGetValue(eventSubscriberId, out eventSubscriber)) eventSubscriber = null; } if (eventSubscriber != null) eventSubscriber.HandleEvent(eventLogEntry); } #endregion #region Internal Methods: Persistent log objects internal static void RegisterPersistentLogObject(DebugLogger debugLogger) { lock (OutstandingLogObjectsLock) { if (!OutstandingLogObjects.Contains(debugLogger)) OutstandingLogObjects.Add(debugLogger); } } internal static void UnregisterPersistentLogObject(DebugLogger debugLogger) { lock (OutstandingLogObjectsLock) { if (OutstandingLogObjects.Contains(debugLogger)) OutstandingLogObjects.Remove(debugLogger); } } #endregion #region Public Events /// <summary> /// An event that is fired when the logging thread is catching an exception. /// </summary> public static event EventHandler<Wayne.Lib.EventArgs<LogException>> OnThreadException; #endregion #region Public Properties /// <summary> /// The current debug log configuration file. /// </summary> [Obsolete("This property is no longer supported. Use the property DebugLoggingConfigured to check whether it's active or not.", true)] public static string DebugConfigFileName { get { return string.Empty; } } /// <summary> /// The current event log configuration file. /// </summary> [Obsolete("This property is no longer supported. Use the property EventLoggingConfigured to check whether it's active or not.", true)] public static string EventConfigFileName { get { return string.Empty; } } /// <summary> /// Is any debug logging configured? /// </summary> public static bool DebugLoggingConfigured { get { return debugConfig.IsConfigured; } } /// <summary> /// Is any event logging configured? /// </summary> public static bool EventLoggingConfigured { get { return eventConfig.IsConfigured; } } /// <summary> /// Should the logger be synchronized or not? /// Default is false (the log writing is performed in another thread). /// </summary> public static bool Synchronized { get; set; } #endregion #region Public Methods: ConfigFile handling /// <summary> /// Clear all loaded log configuration . /// </summary> public static void ClearConfigFiles() { if (!active) return; DebugConfigFileNameList.Clear(); EventConfigFileNameList.Clear(); DebugConfigFilesList.Clear(); EventConfigFilesList.Clear(); DebugConfigBuilderList.Clear(); EventConfigBuilderList.Clear(); LeftoverLinesLogConfigOutputs.Clear(); LeftoverEntitiesLogConfigOutputs.Clear(); RefreshConfig(); } /// <summary> /// Reloads the configuration from the specified configuration file. /// </summary> /// <param name="debugConfigFileName">Log configuration for the debug logging.</param> /// <param name="eventConfigFileName">Log configuration for the event logging.</param> public static void SetConfigFile(string debugConfigFileName, string eventConfigFileName) { if (!active) return; ClearConfigFiles(); AddDebugConfigFile(debugConfigFileName); AddEventConfigFile(eventConfigFileName); } /// <summary> /// Reloads the configuration from the specified configuration file for the debug logging. To activate the event logging /// SetConfigFile(string,string) should be called. /// </summary> /// <param name="debugConfigFileName">Log configuration for the debug logging.</param> public static void SetConfigFile(string debugConfigFileName) { if (!active) return; ClearConfigFiles(); AddDebugConfigFile(debugConfigFileName); } /// <summary> /// Reloads the configuration, adding the given debug log config file. /// </summary> /// <param name="debugConfigFileName">Log configuration for the debug logging.</param> public static void AddDebugConfigFile(string debugConfigFileName) { if (!active) return; DebugConfigFileNameList.Add(debugConfigFileName); RefreshConfig(); } /// <summary> /// Reloads the configuration, adding the given debug log config file. /// </summary> /// <param name="logConfigBuilders">Log configurations for the debug logging.</param> public static void AddDebugConfigFile(params LogConfigBuilder[] logConfigBuilders) { if (!active) return; DebugConfigBuilderList.AddRange(logConfigBuilders); RefreshConfig(); } /// <summary> /// Reloads the configuration, adding the given debug log config file. /// </summary> /// <param name="debugConfigFileStream">Log configuration for the debug logging.</param> public static void AddDebugConfigFile(Stream debugConfigFileStream) { AddDebugConfigFile(debugConfigFileStream, Encoding.UTF8); } /// <summary> /// Reloads the configuration, adding the given debug log config file. /// </summary> /// <param name="debugConfigFileStream">Log configuration for the debug logging.</param> /// <param name="encoding">The encoding of the stream.</param> public static void AddDebugConfigFile(Stream debugConfigFileStream, Encoding encoding) { if (!active) return; DebugConfigFilesList.Add(GetFileLines(debugConfigFileStream, encoding)); RefreshConfig(); } /// <summary> /// Reloads the configuration, adding the given event log config file. /// </summary> /// <param name="eventConfigFileName">Log configuration for the event logging.</param> public static void AddEventConfigFile(string eventConfigFileName) { if (!active) return; EventConfigFileNameList.Add(eventConfigFileName); RefreshConfig(); } /// <summary> /// Reloads the configuration, adding the given event log config file. /// </summary> /// <param name="logConfigBuilders">Log configurations for the event logging.</param> public static void AddEventConfigFile(params LogConfigBuilder[] logConfigBuilders) { if (!active) return; EventConfigBuilderList.AddRange(logConfigBuilders); RefreshConfig(); } /// <summary> /// Reloads the configuration, adding the given event log config file. /// </summary> /// <param name="eventConfigFileStream">Log configuration for the event logging.</param> public static void AddEventConfigFile(Stream eventConfigFileStream) { AddDebugConfigFile(eventConfigFileStream, Encoding.UTF8); } /// <summary> /// Reloads the configuration, adding the given event log config file. /// </summary> /// <param name="eventConfigFileStream">Log configuration for the event logging.</param> /// <param name="encoding">The encoding of the stream.</param> public static void AddEventConfigFile(Stream eventConfigFileStream, Encoding encoding) { if (!active) return; EventConfigFilesList.Add(GetFileLines(eventConfigFileStream, encoding)); RefreshConfig(); } /// <summary> /// Reloads the configuration, adding the given leftover log line output. /// </summary> /// <param name="output">An output to receive leftover log lines.</param> public static void AddLeftoverLinesOutput(LogConfigOutput output) { if (!active) return; LeftoverLinesLogConfigOutputs.Add((LogConfigOutput)output.Clone()); RefreshConfig(); } /// <summary> /// Reloads the configuration, adding the given leftover log entity output. /// </summary> /// <param name="output">An output to receive leftover log entities.</param> public static void AddLeftoverEntitiesOutput(LogConfigOutput output) { if (!active) return; LeftoverEntitiesLogConfigOutputs.Add((LogConfigOutput)output.Clone()); RefreshConfig(); } private static string[] GetFileLines(Stream fileStream, Encoding encoding) { List<string> lines = new List<string>(); using (StreamReader reader = new StreamReader(fileStream, encoding)) { while (!reader.EndOfStream) lines.Add(reader.ReadLine()); } return lines.ToArray(); } #endregion #region Public Methods: Refresh /// <summary> /// Re-loads the configuration for the logging. /// </summary> [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")] public static void RefreshConfig() { if (!active) return; InitDebugMarkerBroadcastListener(); // Refresh the DebugConfig. List<string[]> debugConfigFiles = new List<string[]>(DebugConfigFilesList); foreach (string fileName in DebugConfigFileNameList) debugConfigFiles.Add(FileSupport.LoadToStringArray(fileName)); if (DebugConfigBuilderList.Count > 0) debugConfigFiles.Add(LogConfigBuilder.GetLogConfigFileLines(DebugConfigBuilderList.ToArray())); DebugConfig.Refresh(debugConfigFiles, LeftoverLinesLogConfigOutputs.ToArray(), LeftoverEntitiesLogConfigOutputs.ToArray()); // Refresh the EventConfig. List<string[]> eventConfigFiles = new List<string[]>(EventConfigFilesList); foreach (string fileName in EventConfigFileNameList) eventConfigFiles.Add(FileSupport.LoadToStringArray(fileName)); if (EventConfigBuilderList.Count > 0) eventConfigFiles.Add(LogConfigBuilder.GetLogConfigFileLines(EventConfigBuilderList.ToArray())); eventConfig.Refresh(eventConfigFiles, new LogConfigOutput[0], new LogConfigOutput[0]); // Start the thread if it's not yet started (first time it's null). if ((loggerThread == null) && (debugConfigFiles.Count > 0)) loggerThread = new LoggerThread(LogType.Debug, debugConfig); if ((eventLoggerThread == null) && (eventConfigFiles.Count > 0)) eventLoggerThread = new LoggerThread(LogType.Event, eventConfig); // To prevent locking the list while iterating, take a copy and iterate through the copy. // The danger of doing this is that an object could be removed after the copy and before its // Invalidate-method is called. But nothing really bad can happen due to this... List<DebugLogger> outstandingLogObjectsCopy; lock (OutstandingLogObjectsLock) { outstandingLogObjectsCopy = new List<DebugLogger>(OutstandingLogObjects); } foreach (DebugLogger debugLogger in outstandingLogObjectsCopy) { try { debugLogger.Invalidate(); } catch (Exception) { } } // Check if the dotNetLog should be active or not. dotNetLog.CheckActive(); } #endregion #region Public Methods: Reset /// <summary> /// Resets the logger completely. /// </summary> public static void Reset() { Close(); active = true; debugConfig = new LogConfig(); eventConfig = new LogConfig(); dotNetLog = new DotNetLog(); globalLogEntryCounter = new GlobalLogEntryCounter(); } #endregion #region Public Methods: Close /// <summary> /// Closes the logger. This should be done as the last things before the application terminates. /// </summary> public static void Close() { if (active) { // Shut down the config. if (debugConfig != null) { debugConfig.Dispose(); debugConfig = null; } if (eventConfig != null) { eventConfig.Dispose(); eventConfig = null; } if (dotNetLog != null) { // Shut down the dotNetLog. dotNetLog.Dispose(); dotNetLog = null; } ExternalLogWriterNameDict.Clear(); ExternalLogWriterWrapperDict.Clear(); // Now we're closed. active = false; // Shut down the loggerThread. if (loggerThread != null) { loggerThread.Dispose(); loggerThread = null; } if (eventLoggerThread != null) { eventLoggerThread.Dispose(); eventLoggerThread = null; } if (debugMarkerBroadcastReceiverSocket != null) { try { if (debugMarkerBroadcastReceiverSocket.Connected) { debugMarkerBroadcastReceiverSocket.Shutdown(SocketShutdown.Both); } } catch { } try { debugMarkerBroadcastReceiverSocket.Close(); } catch { } debugMarkerBroadcastReceiverSocket = null; } if (globalLogEntryCounter != null) { globalLogEntryCounter.Dispose(); globalLogEntryCounter = null; } debugMarkerBroadcastAddress = null; DebugConfigFileNameList.Clear(); DebugConfigFilesList.Clear(); EventConfigFileNameList.Clear(); EventConfigFilesList.Clear(); DebugConfigBuilderList.Clear(); EventConfigBuilderList.Clear(); OutstandingLogObjects.Clear(); EventSubscriberDict.Clear(); LeftoverLinesLogConfigOutputs.Clear(); LeftoverEntitiesLogConfigOutputs.Clear(); Synchronized = false; } } #endregion #region Public Methods: LogEntry /// <summary> /// Logs the given LogEntry. /// </summary> /// <param name="logEntry">The LogEntry to log.</param> public static void AddEntry(LogEntry logEntry) { if (!active) return; if (loggerThread != null) loggerThread.AddEntry(logEntry); if ((eventLoggerThread != null) && (logEntry is EventLogEntry)) eventLoggerThread.AddEntry(logEntry); // eventThread has higher priority? } /// <summary> /// Logs the given ExceptionLogEntry. /// </summary> /// <param name="logEntry">The LogEntry to log.</param> public static void AddExceptionLogEntry(ExceptionLogEntry logEntry) { AddEntry(logEntry); } /// <summary> /// Logs the given ErrorLogEntry. /// </summary> /// <param name="logEntry">The LogEntry to log.</param> public static void AddErrorLogEntry(ErrorLogEntry logEntry) { AddEntry(logEntry); } /// <summary> /// Logs the given EventLogEntry. /// </summary> /// <param name="logEntry">The LogEntry to log.</param> public static void AddEventLogEntry(EventLogEntry logEntry) { AddEntry(logEntry); } #endregion #region Public Methods: Unregister entity /// <summary> /// Removes the specified entity from the internal filter buffers. /// </summary> /// <param name="entity"></param> public static void UnregisterEntity(IIdentifiableEntity entity) { if (debugConfig != null) debugConfig.UnregisterEntity(entity); if (eventConfig != null) eventConfig.UnregisterEntity(entity); } #endregion #region Public Methods for Event Subscribers /// <summary> /// Remove an event log from the storage. This method should be called from a registered IEventSubscriber when /// it has handled an event. /// </summary> /// <param name="eventSubscriber"></param> /// <param name="eventLogEntry"></param> public static void EventLogHandled(IEventSubscriber eventSubscriber, EventLogEntry eventLogEntry) { //eventLogStorage.Remove(eventSubscriber, eventLogEntry); } /// <summary> /// Register an IEventSubscriber, so it can start receiving events. The event subscriber will be sent the pending events that /// has been stored since the subscriber was registered the last time. /// </summary> /// <param name="eventSubscriber"></param> public static void RegisterEventSubscriber(IEventSubscriber eventSubscriber) { if (eventSubscriber == null) throw new ArgumentNullException("eventSubscriber"); lock (EventSubscriberDictSyncObj) { EventSubscriberDict[eventSubscriber.SubscriberId] = eventSubscriber; } //EventLogEntry[] entries = eventLogStorage.GetPendingEvents(eventSubscriber.SubscriberId); //foreach (EventLogEntry entry in entries) // eventSubscriber.HandleEvent(entry); } /// <summary> /// Unregister a registered IEventSubscriber. /// </summary> /// <param name="eventSubscriber"></param> public static void UnregisterEventSubscriber(IEventSubscriber eventSubscriber) { if (eventSubscriber == null) throw new ArgumentNullException("eventSubscriber"); lock (EventSubscriberDictSyncObj) { EventSubscriberDict.Remove(eventSubscriber.SubscriberId); } } #endregion #region ExternalLogging private static string GetExternalLogWriterKey(ExternalLogWriter externalLogWriter) { return string.Format("{0}#{1}", externalLogWriter.ExternalLogType, externalLogWriter.ExternalLogName); } private static string GetExternalLogWriterKey(ExternalLogWriterWrapper externalLogWriterWrapper) { return string.Format("{0}#{1}", externalLogWriterWrapper.ExternalLogType, externalLogWriterWrapper.ExternalLogName); } /// <summary> /// Register an ExternalLogWriter. /// </summary> /// <param name="externalLogWriter">The external log writer to register.</param> public static void RegisterExternalLogger(ExternalLogWriter externalLogWriter) { if (ExternalLogWriterDictSyncObj != null) lock (ExternalLogWriterDictSyncObj) ExternalLogWriterNameDict[GetExternalLogWriterKey(externalLogWriter)] = externalLogWriter; } /// <summary> /// Unregister an ExternalLogWriter. /// </summary> /// <param name="externalLogWriter">The external log writer to unregister.</param> public static void UnregisterExternalLogger(ExternalLogWriter externalLogWriter) { if (ExternalLogWriterDictSyncObj != null) lock (ExternalLogWriterDictSyncObj) { ExternalLogWriterNameDict.Remove(GetExternalLogWriterKey(externalLogWriter)); bool found; do { found = false; foreach (KeyValuePair<ExternalLogWriterWrapper, ExternalLogWriter> pair in ExternalLogWriterWrapperDict) { if (pair.Value == externalLogWriter) { ExternalLogWriterWrapperDict.Remove(pair.Key); found = true; break; } } } while (found); } } [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] internal static void PerformExternalLogEntry(ExternalLogWriterWrapper externalLogWriterWrapper, LogEntry logEntry) { if (ExternalLogWriterDictSyncObj != null) { lock (ExternalLogWriterDictSyncObj) { ExternalLogWriter externalLogWriter; if (!ExternalLogWriterWrapperDict.TryGetValue(externalLogWriterWrapper, out externalLogWriter)) { if (ExternalLogWriterNameDict.TryGetValue(GetExternalLogWriterKey(externalLogWriterWrapper), out externalLogWriter)) { externalLogWriter.InitParametersInternal(externalLogWriterWrapper.Parameters); ExternalLogWriterWrapperDict[externalLogWriterWrapper] = externalLogWriter; } } if (externalLogWriter != null) { try { if (externalLogWriter.Active) { string text = LogTextWriting.GetLogEntryText(externalLogWriterWrapper, logEntry, externalLogWriterWrapper.WritingParameters); externalLogWriter.LogInternal(logEntry, text); } } catch { } } } } } /// <summary> /// Get the LogTextWritingParameters for the requested ExternalLogWriter. /// </summary> /// <param name="externalLogWriter">The ExternalLogWriter to get the parameters of.</param> [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#")] internal static LogTextWritingParameters GetExternalLoggerWritingParameters(ExternalLogWriter externalLogWriter) { if (ExternalLogWriterDictSyncObj != null) { lock (ExternalLogWriterDictSyncObj) { foreach (KeyValuePair<ExternalLogWriterWrapper, ExternalLogWriter> pair in ExternalLogWriterWrapperDict) { if (pair.Value == externalLogWriter) { return pair.Key.WritingParameters; } } } } return null; } #endregion #region Debug Marker Broadcasting /// <summary> /// Broadcasts a debug marker to be inserted into all active logfiles. /// </summary> /// <param name="debugMarker">The text to insert into all the log files.</param> // public static void InjectDebugMarker(string debugMarker) // { // try // { // System.Net.Sockets.Socket transmitterSocket = null; // try // { // try // { //transmitterSocket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.IP); // transmitterSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); // var lingerOption = new LingerOption(true, 0); // transmitterSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lingerOption); // transmitterSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, 1); // transmitterSocket.Bind(new IPEndPoint(IPAddress.Any, 0)); // Bind the socket to the "any" end point. // byte[] data = Encoding.UTF8.GetBytes(debugMarker); // int offset = 0; // int size = data.Length; // if (size > DebugMarkerBroadcastReceiverBuffer.Length) // size = DebugMarkerBroadcastReceiverBuffer.Length; // int currentSentSize; // do // { // currentSentSize = transmitterSocket.SendTo(data, offset, size, SocketFlags.None, GetDebugMarkerBroadcastIPEndPoint()); // offset += currentSentSize; // size -= currentSentSize; // } // while ((size > 0) && (currentSentSize > 0)); // } // catch (Exception) { } // } // finally // { // if (transmitterSocket != null) // { // try // { // transmitterSocket.Shutdown(SocketShutdown.Both); // } // finally // { // transmitterSocket.Close(); // } // } // } // } // catch (Exception) { } // } private static void InitDebugMarkerBroadcastListener() { if (debugMarkerBroadcastReceiverSocket == null) { try { debugMarkerBroadcastReceiverSocket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.IP); debugMarkerBroadcastReceiverSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1); //debugMarkerBroadcastReceiverSocket.Bind(new IPEndPoint(IPAddress.Any, GetDebugMarkerBroadcastIPEndPoint().Port)); // Bind the socket to the "any" end point. debugMarkerBroadcastReceiverSocket.BeginReceive(DebugMarkerBroadcastReceiverBuffer, 0, DebugMarkerBroadcastReceiverBuffer.Length, 0, ReceiveCallback, debugMarkerBroadcastReceiverSocket); // Start to listen. } catch { try { debugMarkerBroadcastReceiverSocket.Close(); } catch (Exception) { } debugMarkerBroadcastReceiverSocket = null; } } } private static void ReceiveCallback(IAsyncResult ar) { if (debugMarkerBroadcastReceiverSocket != null) { try { try { System.Net.Sockets.Socket socket = (System.Net.Sockets.Socket)ar.AsyncState; int bytesReceived = 0; try { try { bytesReceived = socket.EndReceive(ar); } catch { } } finally { if (bytesReceived > 0) { string debugMarker = Encoding.UTF8.GetString(DebugMarkerBroadcastReceiverBuffer, 0, bytesReceived); AddEntry(new DebugMarkerLogEntry(debugMarker)); } } } finally { if (active) debugMarkerBroadcastReceiverSocket.BeginReceive(DebugMarkerBroadcastReceiverBuffer, 0, DebugMarkerBroadcastReceiverBuffer.Length, 0, ReceiveCallback, debugMarkerBroadcastReceiverSocket); } } catch { } } } //[System.Diagnostics.DebuggerStepThrough()] //private static IPEndPoint GetDebugMarkerBroadcastIPEndPoint() //{ // try // { // if (debugMarkerBroadcastAddress == null) // { // using (Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"Software\Dresser Wayne\ISM Nucleus\TCP IP\UDP Broadcast", false)) // { // IPAddress broadcastAddress; // int broadcastPort; // if (key != null) // { // broadcastAddress = IPAddress.Parse((string)key.GetValue("BroadcastAddress", "255.255.255.255")); // broadcastPort = (int)key.GetValue("LogMarkerInjectorPort", DefaultDebugMarkerBroadcastPort); // } // else // { // broadcastPort = DefaultDebugMarkerBroadcastPort; // broadcastAddress = IPAddress.Broadcast; // } // if (broadcastAddress != null) // debugMarkerBroadcastAddress = new IPEndPoint(broadcastAddress, broadcastPort); // } // } // } // catch // { // if (debugMarkerBroadcastAddress == null) // debugMarkerBroadcastAddress = new IPEndPoint(IPAddress.Broadcast, DefaultDebugMarkerBroadcastPort); // } // return debugMarkerBroadcastAddress; //} #endregion #region DateTimeToString internal static string DateTimeToString(DateTime dateTime, string dateTimeFormat) { if (GlobalLogEntryCounter != null) return DateTimeToString(dateTime, dateTimeFormat, GlobalLogEntryCounter.GetNextValue()); return DateTimeToString(dateTime, dateTimeFormat, 0); } internal static string DateTimeToString(DateTime dateTime, string dateTimeFormat, UInt64 logEntryIndex) { return FormatDateTime(dateTime) + "[" + logEntryIndex.ToString("00000") + "]"; } private static string FormatDateTime(DateTime dt) { char[] chars = new char[12]; Write2Chars(chars, 0, dt.Hour); chars[2] = ':'; Write2Chars(chars, 3, dt.Minute); chars[5] = ':'; Write2Chars(chars, 6, dt.Second); chars[8] = '.'; Write2Chars(chars, 9, dt.Millisecond / 10); chars[11] = Digit(dt.Millisecond % 10); return new string(chars); } private static void Write2Chars(char[] chars, int offset, int value) { chars[offset] = Digit(value / 10); chars[offset + 1] = Digit(value % 10); } private static char Digit(int value) { return (char)(value + '0'); } #endregion } }