// Copyright Keysight Technologies 2012-2019 // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, you can obtain one at http://mozilla.org/MPL/2.0/. using System; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; namespace OpenTap.Diagnostic { /// /// Log source interface. Instances of this are always created by a corresponding ILogContext. /// [ComVisible(false)] public interface ILog { /// /// Logs an event. /// /// Event type constant. Typically matches System.Diagnostics.TraceEventType. /// Message for the event. void LogEvent(int EventType, string Message); /// /// Logs an event. /// /// Event type constant. Typically matches System.Diagnostics.TraceEventType. /// Message for the event. Formatted with arguments in Args. /// Arguments for String.Format() call. void LogEvent(int EventType, string Message, params object[] Args); /// /// Logs an event. /// /// Event type constant. Typically matches System.Diagnostics.TraceEventType. /// Duration in nanoseconds of this event. /// Message for the event. void LogEvent(int EventType, long DurationNS, string Message); /// /// Logs an event. /// /// Event type constant. Typically matches System.Diagnostics.TraceEventType. /// Duration in nanoseconds of this event. /// Message for the event. Formatted with arguments in Args. /// Arguments for String.Format() call. void LogEvent(int EventType, long DurationNS, string Message, params object[] Args); /// /// Identifier name of this source. /// string Source { get; } } /// /// A structure containing all information about an event. /// public struct Event { /// /// Construct new structure. /// /// The duration of the event in nanoseconds. /// The event type this event was logged with. /// The message for the event. /// The log source identifier this event was logged from. /// The timestamp for the event in system ticks. public Event(long duration, int eventType, string message, string source, long timestamp) { DurationNS = duration; EventType = eventType; Message = message; Source = source; Timestamp = timestamp; } /// /// The event type this event was logged with. Typically matches System.Diagnostics.TraceEventType. /// public int EventType; /// /// The log source identifier this event was logged from. /// public string Source; /// /// The Timestamp for the event in Ticks. /// public long Timestamp; /// /// The duration of the event in nanoseconds. /// public long DurationNS; /// /// The message for the event. /// public string Message; /// Creates a string representation of this event structure. public override string ToString() => $"{Timestamp} : {Source} : {Message}"; } /// /// A collection class that provide posibility to iterate over an array of events /// internal class EventCollection : IEnumerable, IDisposable { #region private fields private Event[] events = null; #endregion #region nested types private class EventCollectionEnumerator : IEnumerator { #region private fields private int index = -1; private EventCollection eventCollection = null; private bool disposed = false; #endregion #region properties public Event Current { get { VerifyNotDisposed(); try { Event element = eventCollection.events[index]; return element; } catch (IndexOutOfRangeException e) { throw new InvalidOperationException(e.Message); } } } object IEnumerator.Current { get { VerifyNotDisposed(); return Current; } } #endregion #region ctor public EventCollectionEnumerator(EventCollection eventCollection) { disposed = false; this.eventCollection = eventCollection; } #endregion public void Dispose() { VerifyNotDisposed(); disposed = true; } public bool MoveNext() { VerifyNotDisposed(); index++; return (index < eventCollection.events.Length); } public void Reset() { VerifyNotDisposed(); index = -1; } private void VerifyNotDisposed() { if (disposed) { throw new ObjectDisposedException("EventCollectionEnumerator"); } else if (eventCollection.Disposed) { throw new ObjectDisposedException("EventCollection"); } } } #endregion #region properties /// /// Returns a boolean indicating whether this instance has been disposed or not. /// public bool Disposed { get { VerifyNotDisposed(); return events == null; } } /// /// Gets the number of the elements in the collection /// public int Length { get { VerifyNotDisposed(); if (events == null) { throw new ObjectDisposedException("EventCollection"); } if (events != null) return events.Length; else return 0; } } #endregion #region ctor /// /// Creates a new instance of . /// /// The event array that will be wrapped around by this class. public EventCollection(Event[] events) { this.events = events; } #endregion /// /// Dispose this instance. /// public void Dispose() { VerifyNotDisposed(); events = null; } /// /// An enumerator that can be used to enumerate this collection. /// /// An enumerator that can be used to enumerate this collection. public IEnumerator GetEnumerator() { VerifyNotDisposed(); return new EventCollectionEnumerator(this); } /// /// An enumerator that can be used to enumerate this collection. /// /// An enumerator that can be used to enumerate this collection. IEnumerator IEnumerable.GetEnumerator() { VerifyNotDisposed(); return new EventCollectionEnumerator(this); } private void VerifyNotDisposed() { if (events == null) { throw new ObjectDisposedException("EventCollection"); } } } /// /// Interface a log listener must implement. /// public interface ILogListener { /// /// Message called when multiple events have been logged. /// /// Array containing a number of events. void EventsLogged(IEnumerable Events); /// /// Called when the log context requests that this listener must flush all of its output resources. /// void Flush(); } /// /// The timestamping mechanism used by ILogContext. /// public interface ILogTimestampProvider : ITapPlugin { /// /// Generates a timestamp for the current instant. /// long Timestamp(); /// /// Converts a timestamp generated by the Timestamp method into Ticks. /// /// long ConvertToTicks(long timestamp); } /// /// A log context that can have multiple log sources and . /// [ComVisible(false)] public interface ILogContext { /// /// Creates a log source with a given source identifier. /// /// The source identifier of this log source. ILog CreateLog(string Source); /// /// Removes a log source from the context. /// /// The given log source. void RemoveLog(ILog LogSource); /// /// Attaches a log listener. /// void AttachListener(ILogListener Listener); /// /// Detaches a log listener. Automatically flushes the context. /// void DetachListener(ILogListener Listener); /// /// Flush all events received at the time instant this method is called, but only waits a number of milliseconds. /// /// Max time to wait for messages. If 0 it will wait infinitely. /// True if it waited successfully, or false if a timeout occurred. bool Flush(int TimeoutMS = 0); /// /// Flush all events received at the time instant this method is called, but only waits a given duration. /// /// Max time to wait for messages, or zero to wait infinitely. /// True if it waited successfully, or false if a timeout occurred. bool Flush(TimeSpan Timeout); /// /// Timestamp method to use for all subsequent logged events. /// ILogTimestampProvider Timestamper { get; set; } /// /// When true, sets the log context to an asynchronous mode (avoiding the potential synchronous mode problem of log sources returning from calls before the events have been processed). /// When false, log sources always wait until all log listeners have processed the events. /// bool Async { get; set; } /// /// Maximum number of outstanding events. Only relevant for mode. /// int MessageBufferSize { get; set; } } /// /// Extended ILogContext interface. /// public interface ILogContext2 : ILogContext { /// Registers a new event /// void AddEvent(Event @event); /// gets if the context has any listeners. bool HasListeners { get; } } }