// 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; }
}
}