Dependency concerns Implementing EventSource for semantic logging in large application
Asked Answered
T

3

7

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?

Tutor answered 12/10, 2014 at 18:30 Comment(3)
I usually use one unique guid, one unique logging class, with one unique enum (defining say "a logging component") plus a TraceLevel (error, warning, info, etc.). Then, the Log method can use the cool [CallerMemberName] so you have the traced method name automatically set. That creates just one reference to a common class (that you can even share with a source link in Visual Studio if you don't want a hard assembly reference).Rubble
@SimonMourier That would work for "generic" logs, but it doesn't seem to work well for semantic logging?Tutor
yes, that was more a comment :)Rubble
J
0

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.
Javanese answered 15/4, 2015 at 17:37 Comment(2)
None of these are all that appealing, but I guess the 3'rd option above at least answers my question; it is possible, but not without a lot of work. :/Tutor
While I was actually hoping to implement solution 3 above, it appears it doesn't work. Because you cannot create two instances of an EventSource class with the same GUID, it will generate an error event saying that `ERROR: Exception in Command Processing for EventSource XXXX: An instance of EventSource with Guid c64e6d39-ff1f-4620-8041-e3f9cca908c9 already exist. :(Tutor
H
0

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

Huihuie answered 15/12, 2015 at 10:12 Comment(0)
T
0

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){
       }
    }
Tomasine answered 11/4, 2017 at 10:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.