CoherentSolutions.Extensions.Hosting.ServiceFabric Release v1.3.0

The new version of CoherentSolutions.Extensions.Hosting.ServiceFabric is released!

The version 1.3.0 is available on NuGet.

The release notes can be found on project version page.

What’s new?

This release brings advanced support for ETW configuration.

Interested? 🙂

Let’s see the details!

Introduction

The ETW is the preferred way of reporting events in Service Fabric. When creating a new project using Service Fabric project template. It creates a default implementation of EventSource class like this:

  [EventSource(Name = "MyCompany-Application4-Web1")]
  internal sealed class ServiceEventSource : EventSource
  {
    // ...

    public static readonly ServiceEventSource Current = 
      new ServiceEventSource();

    #region Keywords

    // ...

    public static class Keywords
    {
      public const EventKeywords Requests 
        = (EventKeywords)0x1L;

      public const EventKeywords ServiceInitialization 
        = (EventKeywords)0x2L;
    }

    // ...

    #endregion

    #region Events

    // ...

    const int MessageEventId = 1;

    [Event(MessageEventId,
      // ...
      )]
    public void Message(
      string message) 
    { 
      // ...
    }

    const int ServiceMessageEventId = 2;

    [Event(ServiceMessageEventId,
      // ...
      )]
    private void ServiceMessage(
      string serviceName,
      string serviceTypeName,
      long replicaOrInstanceId,
      Guid partitionId,
      string applicationName,
      string applicationTypeName,
      string nodeName,
      string message)
    {
      // ...
    }

    const int ServiceTypeRegisteredEventId = 3;

    [Event(ServiceTypeRegisteredEventId,
      // ...
      )]
    public void ServiceTypeRegistered(
      int hostProcessId, 
      string serviceType)
    {
      // ...
    }

    const int ServiceHostInitializationFailedEventId = 4;

    [Event(ServiceHostInitializationFailedEventId,
      // ...
      )]
    public void ServiceHostInitializationFailed(
      string exception)
    {
      // ...
    }

    const int ServiceRequestStartEventId = 5;

    [Event(ServiceRequestStartEventId,
      // ...
      )]
    public void ServiceRequestStart(
      string requestTypeName)
    {
      // ...
    }

    const int ServiceRequestStopEventId = 6;

    [Event(ServiceRequestStopEventId,
      // ...
      )]
    public void ServiceRequestStop(
      string requestTypeName, 
      string exception = "")
    {
      // ...
    }

    // ...

    #endregion
  }
	

The ServiceEventSource is used like this:

  ServiceEventSource
    .Current
    .ServiceTypeRegistered(
      Process.GetCurrentProcess().Id, 
      typeof(Web1).Name);
	

There are multiple advantages of using the predefined event sources: better debugging experience in Visual Studio, ability to generate ETW manifest, etc.

Starting from the beginning CoherentSolutions.Extensions.Hosting.ServiceFabric supports auto-generation of self-descriptive event source and redirection of ILogger<T> events to this event source (see understanding logging wiki page for more information). The infrastructure was automatically gathering additional information depending on the source of event and attaching it as event payload.

This implementation had one major disadvantage – there were no way to redirect events to predefined event source.

Now this and related things can be changed using new event source reconfiguration.

Reconfiguring Event Source

The reconfiguration of event source is done using new SetupEventSource method:

  .DefineStatefulService(
    serviceBuilder =>
    {
      serviceBuilder
        .SetupEventSource(
          eventSourceBuilder => { ... });
    })
  

Inside the SetupEventSource method we can use UseImplementation method to override the factory function used to instantiate event source implementation:

  .DefineStatefulService(
    serviceBuilder =>
    {
      serviceBuilder
        .SetupEventSource(
          eventSourceBuilder =>
          {
            eventSourceBuilder
              .UseImplementation(
                () => ServiceEventSource.Current);
          })
    })
  

Before we would be able to specify ServiceEventSource as an implementation it should implement the IServiceEventSource interface. This is required to support automated event redirection from ILogger<T>:

  public interface IServiceEventSource
  {
    void WriteEvent<T>(ref T eventData)
      where T : ServiceEventSourceData;
  }
  

Here is the example of how the IServiceEventSource can be implemented to redirect all event as ServiceMessage event.

  [EventSource(Name = "MyCompany-Application4-Web1")]
  internal sealed class ServiceEventSource 
      : EventSource, IServiceEventSource
  {
    // ...

    public void WriteEvent<T>(
      ref T eventData)
      where T : ServiceEventSourceData
    {
      this.ServiceMessage(
        eventData.ServiceName,
        eventData.ServiceTypeName,
        eventData.ReplicaOrInstanceId,
        eventData.PartitionId,
        eventData.ApplicationName,
        eventData.ApplicationTypeName,
        eventData.NodeName,
        eventData.EventMessage);
    }
  
    [Event(ServiceMessageEventId, 
      Level = EventLevel.Informational, 
      Message = "{7}")]
    private void ServiceMessage(
      string serviceName,
      string serviceTypeName,
      long replicaOrInstanceId,
      Guid partitionId,
      string applicationName,
      string applicationTypeName,
      string nodeName,
      string message)
    {
      this.WriteEvent(
        ServiceMessageEventId,
        serviceName,
        serviceTypeName,
        replicaOrInstanceId,
        partitionId,
        applicationName,
        applicationTypeName,
        nodeName,
        message);
    }

    // ...
  }
  

The main advantage is that implementation now has control over how events from ILogger<T> pipeline are redirected.

While this feature improved the mechanism of event redirection it doesn’t help with the ServiceEventSource.Current usage. Fortunately current release made an improvement there too.

Specialized Interfaces

Imagine that you have and event raised each time a GetValue method is invoked:

  [EventSource(Name = "MyCompany-Application4-Web1")]
  internal sealed class ServiceEventSource 
      : EventSource, IServiceEventSource
  {
    // ...

    public static class Keywords
    {
      // ...

      public const EventKeywords ApiController 
        = (EventKeywords) 0x4L;

      // ...
    }

    // ...

    private const int GetValueMethodInvokedId = 7;

    [Event(GetValueMethodInvokedId, 
      // ...
      )]
    public void GetValueMethodInvoked()
    {
      // ...
    }

    // ...
  }
  

You can try to use ILogger<T> pipeline and write some metadata in order to identify this event in ServiceEventSource class or you can use ServiceEventSource.Current.GetValueMethodInvoked directly where it is required or you can write an abstraction and use it through dependency injection.

All of the above methods have their disadvantages: complex logic, uncontrolled usage of global object, need to write unnecessary code. As it is mentioned on the project page one of the main goals of CoherentSolutions.Extensions.Hosting.ServiceFabric is to remove unnecessary code. That is why it does implements the third option for you.

All you need to do is to:

  1. Define a desired interface and inherit in from IServiceEventSourceInterface:

          public interface IApiServiceEventSource 
            : IServiceEventSourceInterface
          {
            void GetValueMethodInvoked();
          }
          
  2. Implement this interface by ServiceEventSource:

          internal sealed class ServiceEventSource 
            : EventSource, 
              IServiceEventSource, 
              IApiServiceEventSource
          {
          }
          

Now when the ServiceEventSource is registered as the event source implementation the infrastructure automatically detects the interfaces derived from IServiceEventSourceInterface and registers implementation instance by these interfaces in all dependency injection containers.

This allows you to write events directly using IApiServiceEventSource interface.

Conclusion

The new release of CoherentSolutions.Extensions.Hosting.ServiceFabric improves the ability to report ETW events by reconfiguring the default self-descriptive event source, by providing control of how events redirected from ILogger<T> pipeline are reported and by providing an ability to easily abstract event source under well formed interfaces.

Thank you for reading!

Acknowledgement

CoherentSolutions.Extensions.Hosting.ServiceFabric is an open source project owned and maintained by Coherent Solutions Inc.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s