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