Search code examples
elasticsearchetwevent-flow

EventFlow - Creating a Custom Filter to attach Source Server Information


I'm assuming this is a pretty common question, how do we easily add Server info to an EventFlow event?

My scenario is that I'm deploying an application that will have its own environment specific EventFlowConfig.json, but each server in the farm will get that same json file. So... how can I tell which server in the farm sent the event to ElasticSearch?

One option is to use .net to get servername and send it as a column, which would require that I add server name to every event. That seems a little excessive but it would do the job. I was hoping there was an easier way besides having to actually code this into an event.

Thanks for your time, Greg

Edit 4 - Karol has been great helping me get this working example up and running, THANK YOU KAROL!!! Attempting to add create a custom filter as an extension:

  1. We need to create a new class for the custom Filter Factory
  2. We then need to create a second new class and have it implement the IFilter interface. To pass the health monitor from the factory we used a constructor.
  3. Use the Evaluate function as our area to add the data (eventData.AddPayloadProperty)
  4. Then refer to the custom filter in the extensions area of our EventFlowConfig.json.
    a. The category is filterFactory

    b. The type is the name of your class.

    c. The qualified type name is in the "type-name, assembly-name”. For example (assuming you name your filter factory ‘MyCustomFilterFactory’): “My.Application.Logging.MyCustomFilterFactory, My.Application.Assembly.WhereCustomFilterAndItsFactoreLive”

  5. Add a reference to Microsoft.Extensions.Configuration where the C# code lives.

  6. Then you can reference your custom filter anywhere you need to, here we are using a global filter

Working example:

   class CustomGlobalFilter : IFilter
{
    private IHealthReporter HealthReporter;
    private string MachineName;
    public CustomGlobalFilter(string ServerName, IHealthReporter HealthReporter)
    {
        MachineName = ServerName;
        this.HealthReporter = HealthReporter;            
    }
FilterResult IFilter.Evaluate(EventData eventData)
    {            
        eventData.AddPayloadProperty("ServerName", MachineName, HealthReporter, "CustomGlobalFilter");
        return FilterResult.KeepEvent;
    }
}

class CustomGlobalFilterFactory : IPipelineItemFactory<CustomGlobalFilter>
{
    public CustomGlobalFilter CreateItem(IConfiguration configuration, IHealthReporter healthReporter)
    {            
        CustomGlobalFilter GlobalFilter = new CustomGlobalFilter(System.Environment.MachineName, healthReporter);            
        return GlobalFilter;
    }
}

Then in the EventFlow Config:

"filters": [
{
  "type": "drop",
  "include": "Level == Verbose"
},
{
   "type":  "CustomGlobalFilter"
}
],
...
"extensions": [
{
  "category": "filterFactory",
  "type": "CustomGlobalFilter",
  "qualifiedTypeName": "My.Company.Presentation.App.CustomGlobalFilter, My.Company.Presentation.App"
}

Solution

  • It is not something that is built into EventFlow today, but there are at least a couple of options:

    1. Use EventFlow extensibility to add a custom filter that adds these properties to every event it “sees”.
    2. In many logging libraries there is a concept of “initializers” or “enrichment” that can be used to automatically add contextual properties. For example in Serilog (which is natively supported by EventFlow)