Dependency concerns Implementing EventSource for s

2019-04-07 03:46发布

问题:

I'm working on a large product consisting of a three windows services and several normal windows applications (.exe). Now we want to move to ETW and Semantic Logging, and use the Microsoft.Diagnostics.Tracing.EventSource.

I read somewhere that all logically connected parts of the application should use the same event source. This means that preferrably we would like to have pretty much a single EventSource for our services. But how can we do this without introducing dependencies among pretty much all the assemblies in the product?

The application currently consists of about 70 assemblies. And to be able to create a log-method in the EventSource that for example accepts an enum-value, the assembly containing the event source has to reference the assembly defining the enum, which means that the enum definition would need to be moved from the assembly using it, an .exe perhaps, to something that is referenced by all assemblies.

Is there some way to have several classes derived from EventSource in one application that still use the same ETW EventSource? Or what would be a good way to implement semantic logging with ETW in a scenario such as this, when it is undesirable to introduce a whole bunch of new dependencies to create your log class?

回答1:

There are three strategies:

  1. Create one assembly that contains only EventSource derived class which defines events for all application. Add reference to that assembly to all required projects. For simplicity you could wrap it into a nuget package.
  2. Create one test project with just one EventSource derived class. Use it for validation purposes only. Copy this class to all required projects. This is basically the same solution but without binary dependencies.
  3. Create new EventSource derived class per each projects, but specify the same Guid attribute for them. In this case you need to make sure that all those event sources have the same declaration for overlapped (with the same ID) events. And in this case you have to write some manifest merge tool to produce combined manifest.


回答2:

Be carefull, EventSource classes must be sealed ! If you want to use dependency injection using EventSource, there is a workaround...

Define a simple interface :

// A simple interface to log what you need ...
public interface ILog
{
    void Debug(string message);

    void Info(string message);

    void Warn(string message);

    void Error(string message);

    void Error(string message, Exception exception);
}

And the implementation ( implementation of your interface must be decorated with the NonEventAttribute :

[EventSource(Name = "MyLogEventsource")]
public class Log : EventSource, ILog
{
    public Log()
    {
        EventSourceAnalyzer.InspectAll(this);
    }

    [NonEvent]
    public void Debug(string message)
    {
        DebugInternal(message);
    }

    [Event(1)]
    private void DebugInternal(string message)
    {
        WriteEvent(1, message);
    }

    [NonEvent]
    public void Info(string message)
    {
        InfoInternal(message);
    }

    [Event(2)]
    private void InfoInternal(string message)
    {
        WriteEvent(2, message);
    }

    [NonEvent]
    public void Warn(string message)
    {
        WarnInternal(message);
    }

    [Event(3)]
    private void WarnInternal(string message)
    {
        WriteEvent(3, message);
    }

    [NonEvent]
    public void Error(string message)
    {
        ErrorInternal(message, "", "");
    }

    [NonEvent]
    public void Error(string message, Exception exception)
    {
        ErrorInternal(message, exception.Message, exception.ToString());
    }

    [Event(4)]
    private void ErrorInternal(string message, string exceptionMessage, string exceptionDetails)
    {
        WriteEvent(4, message, exceptionMessage, exceptionDetails);
    }
}

you can now inject your logging class ^^



回答3:

I usually do this so that there is segregation of interfaces even though they use a single instance of an event source. In my ioc all code with ISingletonDependency are registered as singleton. So you can call interfaces with very specific methods but they are still the same EventSource.

Hope this helps.

public MyCompanyEventSource: IMyCompanyEventSource, ISingletonDependency{
}
public IMyCompanyEventSource: IComponentLogger1, IComponentLogger2, IComponentLogger3{
}
public Component1{
       public Component1(IComponentLogger logger){
       }
    }