using System; using System.Collections.Generic; using System.Diagnostics.Tracing; using System.Fabric; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.ServiceFabric.Services.Runtime; namespace ApiGw_Base { [EventSource(Name = "MyCompany-eShopOnServiceFabricOcelote-ApiGw_Base")] internal sealed class ServiceEventSource : EventSource { public static readonly ServiceEventSource Current = new ServiceEventSource(); static ServiceEventSource() { // A workaround for the problem where ETW activities do not get tracked until Tasks infrastructure is initialized. // This problem will be fixed in .NET Framework 4.6.2. Task.Run(() => { }); } // Instance constructor is private to enforce singleton semantics private ServiceEventSource() : base() { } #region Keywords // Event keywords can be used to categorize events. // Each keyword is a bit flag. A single event can be associated with multiple keywords (via EventAttribute.Keywords property). // Keywords must be defined as a public class named 'Keywords' inside EventSource that uses them. public static class Keywords { public const EventKeywords Requests = (EventKeywords)0x1L; public const EventKeywords ServiceInitialization = (EventKeywords)0x2L; } #endregion #region Events // Define an instance method for each event you want to record and apply an [Event] attribute to it. // The method name is the name of the event. // Pass any parameters you want to record with the event (only primitive integer types, DateTime, Guid & string are allowed). // Each event method implementation should check whether the event source is enabled, and if it is, call WriteEvent() method to raise the event. // The number and types of arguments passed to every event method must exactly match what is passed to WriteEvent(). // Put [NonEvent] attribute on all methods that do not define an event. // For more information see https://msdn.microsoft.com/en-us/library/system.diagnostics.tracing.eventsource.aspx [NonEvent] public void Message(string message, params object[] args) { if (this.IsEnabled()) { string finalMessage = string.Format(message, args); Message(finalMessage); } } private const int MessageEventId = 1; [Event(MessageEventId, Level = EventLevel.Informational, Message = "{0}")] public void Message(string message) { if (this.IsEnabled()) { WriteEvent(MessageEventId, message); } } [NonEvent] public void ServiceMessage(ServiceContext serviceContext, string message, params object[] args) { if (this.IsEnabled()) { string finalMessage = string.Format(message, args); ServiceMessage( serviceContext.ServiceName.ToString(), serviceContext.ServiceTypeName, GetReplicaOrInstanceId(serviceContext), serviceContext.PartitionId, serviceContext.CodePackageActivationContext.ApplicationName, serviceContext.CodePackageActivationContext.ApplicationTypeName, serviceContext.NodeContext.NodeName, finalMessage); } } // For very high-frequency events it might be advantageous to raise events using WriteEventCore API. // This results in more efficient parameter handling, but requires explicit allocation of EventData structure and unsafe code. // To enable this code path, define UNSAFE conditional compilation symbol and turn on unsafe code support in project properties. private const int ServiceMessageEventId = 2; [Event(ServiceMessageEventId, Level = EventLevel.Informational, Message = "{7}")] private #if UNSAFE unsafe #endif void ServiceMessage( string serviceName, string serviceTypeName, long replicaOrInstanceId, Guid partitionId, string applicationName, string applicationTypeName, string nodeName, string message) { #if !UNSAFE WriteEvent(ServiceMessageEventId, serviceName, serviceTypeName, replicaOrInstanceId, partitionId, applicationName, applicationTypeName, nodeName, message); #else const int numArgs = 8; fixed (char* pServiceName = serviceName, pServiceTypeName = serviceTypeName, pApplicationName = applicationName, pApplicationTypeName = applicationTypeName, pNodeName = nodeName, pMessage = message) { EventData* eventData = stackalloc EventData[numArgs]; eventData[0] = new EventData { DataPointer = (IntPtr) pServiceName, Size = SizeInBytes(serviceName) }; eventData[1] = new EventData { DataPointer = (IntPtr) pServiceTypeName, Size = SizeInBytes(serviceTypeName) }; eventData[2] = new EventData { DataPointer = (IntPtr) (&replicaOrInstanceId), Size = sizeof(long) }; eventData[3] = new EventData { DataPointer = (IntPtr) (&partitionId), Size = sizeof(Guid) }; eventData[4] = new EventData { DataPointer = (IntPtr) pApplicationName, Size = SizeInBytes(applicationName) }; eventData[5] = new EventData { DataPointer = (IntPtr) pApplicationTypeName, Size = SizeInBytes(applicationTypeName) }; eventData[6] = new EventData { DataPointer = (IntPtr) pNodeName, Size = SizeInBytes(nodeName) }; eventData[7] = new EventData { DataPointer = (IntPtr) pMessage, Size = SizeInBytes(message) }; WriteEventCore(ServiceMessageEventId, numArgs, eventData); } #endif } private const int ServiceTypeRegisteredEventId = 3; [Event(ServiceTypeRegisteredEventId, Level = EventLevel.Informational, Message = "Service host process {0} registered service type {1}", Keywords = Keywords.ServiceInitialization)] public void ServiceTypeRegistered(int hostProcessId, string serviceType) { WriteEvent(ServiceTypeRegisteredEventId, hostProcessId, serviceType); } private const int ServiceHostInitializationFailedEventId = 4; [Event(ServiceHostInitializationFailedEventId, Level = EventLevel.Error, Message = "Service host initialization failed", Keywords = Keywords.ServiceInitialization)] public void ServiceHostInitializationFailed(string exception) { WriteEvent(ServiceHostInitializationFailedEventId, exception); } // A pair of events sharing the same name prefix with a "Start"/"Stop" suffix implicitly marks boundaries of an event tracing activity. // These activities can be automatically picked up by debugging and profiling tools, which can compute their execution time, child activities, // and other statistics. private const int ServiceRequestStartEventId = 5; [Event(ServiceRequestStartEventId, Level = EventLevel.Informational, Message = "Service request '{0}' started", Keywords = Keywords.Requests)] public void ServiceRequestStart(string requestTypeName) { WriteEvent(ServiceRequestStartEventId, requestTypeName); } private const int ServiceRequestStopEventId = 6; [Event(ServiceRequestStopEventId, Level = EventLevel.Informational, Message = "Service request '{0}' finished", Keywords = Keywords.Requests)] public void ServiceRequestStop(string requestTypeName, string exception = "") { WriteEvent(ServiceRequestStopEventId, requestTypeName, exception); } #endregion #region Private methods private static long GetReplicaOrInstanceId(ServiceContext context) { StatelessServiceContext stateless = context as StatelessServiceContext; if (stateless != null) { return stateless.InstanceId; } StatefulServiceContext stateful = context as StatefulServiceContext; if (stateful != null) { return stateful.ReplicaId; } throw new NotSupportedException("Context type not supported."); } #if UNSAFE private int SizeInBytes(string s) { if (s == null) { return 0; } else { return (s.Length + 1) * sizeof(char); } } #endif #endregion } }