public TableStorageEventListener(IConfigurationProvider configurationProvider, IHealthReporter healthReporter)
            : base(configurationProvider, healthReporter)
        {
            if (this.Disabled)
            {
                return;
            }

            Debug.Assert(configurationProvider != null);
            this.CreateTableClient(configurationProvider);

            Random randomNumberGenerator = new Random();
            this.instanceId = randomNumberGenerator.Next(100000000).ToString("D8");

            this.nextEntityId = 0;
            this.identityIdResetLock = new object();

            this.Sender = new ConcurrentEventSender<EventData>(
                eventBufferSize: 1000,
                maxConcurrency: MaxConcurrentPartitions,
                batchSize: 50,
                noEventsDelay: TimeSpan.FromMilliseconds(1000),
                transmitterProc: this.SendEventsAsync,
                healthReporter: healthReporter);
        }
        public BufferingEventListener(IConfigurationProvider configurationProvider, IHealthReporter healthReporter)
        {
            if (configurationProvider == null)
            {
                throw new ArgumentNullException("configurationProvider");
            }

            if (healthReporter == null)
            {
                throw new ArgumentNullException("healthReporter");
            }
            this.healthReporter = healthReporter;
            this.errorReportingThrottle = new TimeSpanThrottle(TimeSpan.FromSeconds(1));

            this.Disabled = !configurationProvider.HasConfiguration;
        }
        public EventHubListener(IConfigurationProvider configurationProvider, IHealthReporter healthReporter) : base(configurationProvider, healthReporter)
        {
            if (this.Disabled)
            {
                return;
            }

            Debug.Assert(configurationProvider != null);
            this.CreateConnectionData(configurationProvider);

            this.Sender = new ConcurrentEventSender<EventData>(
                eventBufferSize: 1000,
                maxConcurrency: ConcurrentConnections,
                batchSize: 50,
                noEventsDelay: TimeSpan.FromMilliseconds(1000),
                transmitterProc: this.SendEventsAsync,
                healthReporter: healthReporter);
        }
        public ApplicationInsightsEventListener(IConfigurationProvider configurationProvider, IHealthReporter healthReporter) : base(configurationProvider, healthReporter)
        {
            if (this.Disabled)
            {
                return;
            }

            Debug.Assert(configurationProvider != null);

            telemetry = new TelemetryClient();
            telemetry.Context.InstrumentationKey = configurationProvider.GetValue(AppInsightsKeyName);

            this.Sender = new ConcurrentEventSender<EventData>(
                eventBufferSize: 1000,
                maxConcurrency: 2,
                batchSize: 100,
                noEventsDelay: TimeSpan.FromMilliseconds(1000),
                transmitterProc: this.SendEventsAsync,
                healthReporter: healthReporter);
        }
        public BufferingEventListener(IConfigurationProvider configurationProvider, IHealthReporter healthReporter)
        {
            if (configurationProvider == null)
            {
                throw new ArgumentNullException("configurationProvider");
            }

            if (healthReporter == null)
            {
                throw new ArgumentNullException("healthReporter");
            }
            this.healthReporter = healthReporter;
            this.errorReportingThrottle = new TimeSpanThrottle(TimeSpan.FromSeconds(1));

            lock (this)  // See OnEventSourceCreated() for explanation why we are locking on 'this' here.
            {
                this.Disabled = !configurationProvider.HasConfiguration;
                EnableInitialSources();
                this.constructed = true;
            }
        }
Beispiel #6
0
        public StdOutput CreateItem(IConfiguration configuration, IHealthReporter healthReporter)
        {
            Requires.NotNull(healthReporter, nameof(healthReporter));

            return(new StdOutput(healthReporter));
        }
Beispiel #7
0
        public static EventData ToEventData(this EventWrittenEventArgs eventSourceEvent, IHealthReporter healthReporter, string context)
        {
            Debug.Assert(healthReporter != null);

            // High-precision event timestamping is availabe on .NET 4.6+ and .NET Core 2.0+
            // For the latter the implementation of DateTime.UtcNow has changed and we do not need to do anything.
            // .NET Core 1.1 will use imprecise timestamp--there is no easy fix for this target.

#if NETSTANDARD1_6
            DateTime now = DateTime.UtcNow;
#else
            DateTime now;
            if (hasPreciseTime)
            {
                GetSystemTimePreciseAsFileTime(out long filetime);
                now = DateTime.FromFileTimeUtc(filetime);
            }
            else
            {
                now = DateTime.UtcNow;
            }
#endif
            EventData eventData = new EventData
            {
                ProviderName = eventSourceEvent.EventSource.Name,
                Timestamp    = now,
                Level        = (LogLevel)(int)eventSourceEvent.Level,
                Keywords     = (long)eventSourceEvent.Keywords
            };

            IDictionary <string, object> payloadData = eventData.Payload;
            payloadData.Add(nameof(eventSourceEvent.EventId), eventSourceEvent.EventId);
            payloadData.Add(nameof(eventSourceEvent.EventName), eventSourceEvent.EventName);
            if (eventSourceEvent.ActivityId != default(Guid))
            {
                payloadData.Add(nameof(EventWrittenEventArgs.ActivityId), ActivityPathDecoder.GetActivityPathString(eventSourceEvent.ActivityId));
            }
            if (eventSourceEvent.RelatedActivityId != default(Guid))
            {
                payloadData.Add(nameof(EventWrittenEventArgs.RelatedActivityId), ActivityPathDecoder.GetActivityPathString(eventSourceEvent.RelatedActivityId));
            }

            try
            {
                if (eventSourceEvent.Message != null)
                {
                    // If the event has a badly formatted manifest, the FormattedMessage property getter might throw
                    payloadData.Add(nameof(eventSourceEvent.Message), string.Format(CultureInfo.InvariantCulture, eventSourceEvent.Message, eventSourceEvent.Payload.ToArray()));
                }
            }
            catch { }

            eventSourceEvent.ExtractPayloadData(eventData, healthReporter, context);

            return(eventData);
        }
Beispiel #8
0
        public DiagnosticPipeline(
            IHealthReporter healthReporter,
            IReadOnlyCollection <IObservable <EventData> > inputs,
            IReadOnlyCollection <IFilter> globalFilters,
            IReadOnlyCollection <EventSink> sinks,
            DiagnosticPipelineConfiguration pipelineConfiguration = null,
            bool disposeDependencies    = false,
            TaskScheduler taskScheduler = null)
        {
            Requires.NotNull(healthReporter, nameof(healthReporter));
            Requires.NotNull(inputs, nameof(inputs));
            Requires.Argument(inputs.Count > 0, nameof(inputs), "There must be at least one input");
            Requires.NotNull(sinks, nameof(sinks));
            Requires.Argument(sinks.Count > 0, nameof(sinks), "There must be at least one sink");

            this.pipelineConfiguration = pipelineConfiguration ?? new DiagnosticPipelineConfiguration();
            taskScheduler = taskScheduler ?? TaskScheduler.Current;

            // An estimatie how many batches of events to allow inside the pipeline.
            // We want to be able to process full buffer of events, but also have enough batches in play in case of high concurrency.
            int MaxNumberOfBatchesInProgress = Math.Max(
                5 * this.pipelineConfiguration.MaxConcurrency,
                this.pipelineConfiguration.PipelineBufferSize / this.pipelineConfiguration.MaxEventBatchSize);

            this.Inputs = inputs;
            this.Sinks  = sinks;

            // Just play nice and make sure there is always something to enumerate on
            this.GlobalFilters = globalFilters ?? new IFilter[0];

            this.HealthReporter          = healthReporter;
            this.cancellationTokenSource = new CancellationTokenSource();
            var propagateCompletion = new DataflowLinkOptions()
            {
                PropagateCompletion = true
            };

            // One disposable for each input subscription.
            this.inputSubscriptions = new List <IDisposable>(inputs.Count);

            var inputBuffer = new BufferBlock <EventData>(
                new DataflowBlockOptions()
            {
                BoundedCapacity   = this.pipelineConfiguration.PipelineBufferSize,
                CancellationToken = this.cancellationTokenSource.Token,
                TaskScheduler     = taskScheduler
            });

            this.pipelineHead = inputBuffer;

            var batcher = new BatchBlock <EventData>(
                this.pipelineConfiguration.MaxEventBatchSize,
                new GroupingDataflowBlockOptions()
            {
                BoundedCapacity   = this.pipelineConfiguration.PipelineBufferSize,
                CancellationToken = this.cancellationTokenSource.Token,
                TaskScheduler     = taskScheduler
            }
                );

            inputBuffer.LinkTo(batcher, propagateCompletion);

            this.batcherTimer = new Timer(
                (unused) => { try { batcher.TriggerBatch(); } catch {} },
                state: null,
                dueTime: TimeSpan.FromMilliseconds(this.pipelineConfiguration.MaxBatchDelayMsec),
                period: TimeSpan.FromMilliseconds(this.pipelineConfiguration.MaxBatchDelayMsec));

            ISourceBlock <EventData[]> sinkSource;
            FilterAction filterTransform;

            if (this.GlobalFilters.Count > 0)
            {
                filterTransform = new FilterAction(
                    this.GlobalFilters,
                    this.cancellationTokenSource.Token,
                    MaxNumberOfBatchesInProgress,
                    this.pipelineConfiguration.MaxConcurrency,
                    healthReporter,
                    taskScheduler);
                var globalFiltersBlock = filterTransform.GetFilterBlock();
                batcher.LinkTo(globalFiltersBlock, propagateCompletion);
                sinkSource = globalFiltersBlock;
            }
            else
            {
                sinkSource = batcher;
            }

            bool usingBroadcastBlock = sinks.Count > 1;

            if (usingBroadcastBlock)
            {
                var broadcaster = new BroadcastBlock <EventData[]>(
                    (events) => events?.Select((e) => e.DeepClone()).ToArray(),
                    new DataflowBlockOptions()
                {
                    BoundedCapacity   = MaxNumberOfBatchesInProgress,
                    CancellationToken = this.cancellationTokenSource.Token,
                    TaskScheduler     = taskScheduler
                });
                sinkSource.LinkTo(broadcaster, propagateCompletion);
                sinkSource = broadcaster;
            }

            this.outputCompletionTasks = new List <Task>(sinks.Count);
            foreach (var sink in sinks)
            {
                ISourceBlock <EventData[]> outputSource = sinkSource;

                if (sink.Filters != null && sink.Filters.Count > 0)
                {
                    filterTransform = new FilterAction(
                        sink.Filters,
                        this.cancellationTokenSource.Token,
                        MaxNumberOfBatchesInProgress,
                        this.pipelineConfiguration.MaxConcurrency,
                        healthReporter,
                        taskScheduler);
                    var filterBlock = filterTransform.GetFilterBlock();

                    if (usingBroadcastBlock)
                    {
                        var lossReportingPropagator = new LossReportingPropagatorBlock <EventData[]>(this.HealthReporter);
                        sinkSource.LinkTo(lossReportingPropagator, propagateCompletion);
                        lossReportingPropagator.LinkTo(filterBlock, propagateCompletion);
                    }
                    else
                    {
                        sinkSource.LinkTo(filterBlock, propagateCompletion);
                    }
                    outputSource = filterBlock;
                }
                else if (usingBroadcastBlock)
                {
                    var lossReportingPropagator = new LossReportingPropagatorBlock <EventData[]>(this.HealthReporter);
                    sinkSource.LinkTo(lossReportingPropagator, propagateCompletion);
                    outputSource = lossReportingPropagator;
                }

                OutputAction outputAction = new OutputAction(
                    sink.Output,
                    this.cancellationTokenSource.Token,
                    MaxNumberOfBatchesInProgress,
                    this.pipelineConfiguration.MaxConcurrency,
                    healthReporter,
                    taskScheduler);
                var outputBlock = outputAction.GetOutputBlock();
                outputSource.LinkTo(outputBlock, propagateCompletion);
                this.outputCompletionTasks.Add(outputBlock.Completion);
            }

            IObserver <EventData> inputBufferObserver = new TargetBlockObserver <EventData>(inputBuffer, this.HealthReporter);

            foreach (var input in inputs)
            {
                this.inputSubscriptions.Add(input.Subscribe(inputBufferObserver));
            }

            this.disposed            = false;
            this.disposeDependencies = disposeDependencies;
        }
Beispiel #9
0
 private DiagnosticPipeline createPipeline(LoggerInput input, IHealthReporter reporter)
 {
     return(new DiagnosticPipeline(reporter, new[] { input }, null, new[] { new EventSink(new FakeOutput(), null) }));
 }
Beispiel #10
0
        private static void CreateItemFactories(
            IConfiguration configuration,
            IHealthReporter healthReporter,
            out IDictionary <string, string> inputFactories,
            out IDictionary <string, string> outputFactories,
            out IDictionary <string, string> filterFactories)
        {
            Debug.Assert(configuration != null);
            Debug.Assert(healthReporter != null);

            inputFactories = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
            inputFactories["EventSource"]        = "Microsoft.Diagnostics.EventFlow.Inputs.EventSourceInputFactory, Microsoft.Diagnostics.EventFlow.Inputs.EventSource, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
            inputFactories["PerformanceCounter"] = "Microsoft.Diagnostics.EventFlow.Inputs.PerformanceCounterInputFactory, Microsoft.Diagnostics.EventFlow.Inputs.PerformanceCounter, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
            inputFactories["Trace"]   = "Microsoft.Diagnostics.EventFlow.Inputs.TraceInputFactory, Microsoft.Diagnostics.EventFlow.Inputs.Trace, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
            inputFactories["Serilog"] = "Microsoft.Diagnostics.EventFlow.Inputs.SerilogInputFactory, Microsoft.Diagnostics.EventFlow.Inputs.Serilog, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";

            outputFactories = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
            outputFactories["ApplicationInsights"] = "Microsoft.Diagnostics.EventFlow.Outputs.ApplicationInsightsOutputFactory, Microsoft.Diagnostics.EventFlow.Outputs.ApplicationInsights, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
            outputFactories["StdOutput"]           = "Microsoft.Diagnostics.EventFlow.Outputs.StdOutputFactory, Microsoft.Diagnostics.EventFlow.Outputs.StdOutput, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
            outputFactories["EventHub"]            = "Microsoft.Diagnostics.EventFlow.Outputs.EventHubOutputFactory, Microsoft.Diagnostics.EventFlow.Outputs.EventHub, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
            outputFactories["ElasticSearch"]       = "Microsoft.Diagnostics.EventFlow.Outputs.ElasticSearchOutputFactory, Microsoft.Diagnostics.EventFlow.Outputs.ElasticSearch, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
            outputFactories["OmsOutput"]           = "Microsoft.Diagnostics.EventFlow.Outputs.OmsOutputFactory, Microsoft.Diagnostics.EventFlow.Outputs.Oms, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";

            filterFactories             = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
            filterFactories["metadata"] = "Microsoft.Diagnostics.EventFlow.Filters.EventMetadataFilterFactory, Microsoft.Diagnostics.EventFlow.Core, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
            filterFactories["drop"]     = "Microsoft.Diagnostics.EventFlow.Filters.DropFilterFactory, Microsoft.Diagnostics.EventFlow.Core, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";

            // read 3rd party plugins
            IConfiguration extensionsConfiguration = configuration.GetSection("extensions");

            foreach (var extension in extensionsConfiguration.GetChildren())
            {
                var extConfig = new ExtensionsConfiguration();
                extension.Bind(extConfig);

                IDictionary <string, string> targetFactories = null;
                if (string.Equals(extConfig.Category, ExtensionCategories.InputFactory, StringComparison.OrdinalIgnoreCase))
                {
                    targetFactories = inputFactories;
                }
                else if (string.Equals(extConfig.Category, ExtensionCategories.OutputFactory, StringComparison.OrdinalIgnoreCase))
                {
                    targetFactories = outputFactories;
                }
                else if (string.Equals(extConfig.Category, ExtensionCategories.FilterFactory, StringComparison.OrdinalIgnoreCase))
                {
                    targetFactories = filterFactories;
                }
                else if (string.Equals(extConfig.Category, ExtensionCategories.HealthReporter, StringComparison.OrdinalIgnoreCase))
                {
                    // Health reporter should have been created earlier, so skip
                    continue;
                }
                else
                {
                    healthReporter.ReportWarning($"Unrecognized extension category: {extConfig.Category}");
                    continue;
                }

                if (!string.IsNullOrEmpty(extConfig.Type) && !string.IsNullOrEmpty(extConfig.QualifiedTypeName))
                {
                    targetFactories[extConfig.Type] = extConfig.QualifiedTypeName;
                }
                else
                {
                    healthReporter.ReportWarning($"Invalid extension configuration is skipped. Category: {extConfig.Category}, Type: {extConfig.Type}, QualifiedTypeName: {extConfig.QualifiedTypeName}");
                }
            }
        }
Beispiel #11
0
        private static List <ItemWithChildren <PipelineItemType, PipelineItemChildType> > ProcessSection <PipelineItemType, PipelineItemChildType>(
            IConfigurationSection configurationSection,
            IHealthReporter healthReporter,
            IDictionary <string, string> itemFactories,
            IDictionary <string, string> childFactories,
            string childSectionName)
        {
            Debug.Assert(!string.IsNullOrWhiteSpace(configurationSection.Key));
            Debug.Assert(healthReporter != null);
            Debug.Assert(itemFactories != null);
            Debug.Assert((string.IsNullOrEmpty(childSectionName) && childFactories == null) || (!string.IsNullOrEmpty(childSectionName) && childFactories != null));

            List <ItemWithChildren <PipelineItemType, PipelineItemChildType> > createdItems = new List <ItemWithChildren <PipelineItemType, PipelineItemChildType> >();

            if (configurationSection == null)
            {
                return(createdItems);
            }

            List <IConfigurationSection> itemConfigurationFragments = configurationSection.GetChildren().ToList();

            foreach (var itemFragment in itemConfigurationFragments)
            {
                ItemConfiguration itemConfiguration = new ItemConfiguration();
                try
                {
                    itemFragment.Bind(itemConfiguration);
                }
                catch
                {
                    ReportInvalidConfigurationFragmentAndThrow(healthReporter, itemFragment);
                }

                string itemFactoryTypeName;
                if (!itemFactories.TryGetValue(itemConfiguration.Type, out itemFactoryTypeName))
                {
                    ReportUnknownItemTypeAndThrow(healthReporter, configurationSection, itemConfiguration);
                }

                IPipelineItemFactory <PipelineItemType> factory;
                PipelineItemType item = default(PipelineItemType);
                try
                {
                    var itemFactoryType = Type.GetType(itemFactoryTypeName, throwOnError: true);
                    factory = Activator.CreateInstance(itemFactoryType) as IPipelineItemFactory <PipelineItemType>;
                    item    = factory.CreateItem(itemFragment, healthReporter);
                }
                catch (Exception e)
                {
                    ReportItemCreationFailedAndThrow(healthReporter, itemConfiguration.Type, e);
                }

                // The factory will do its own error reporting, so if it returns null, no further error reporting is necessary.
                if (item == null)
                {
                    continue;
                }

                List <ItemWithChildren <PipelineItemChildType, object> > children = null;
                if (!string.IsNullOrEmpty(childSectionName))
                {
                    IConfigurationSection childrenSection = itemFragment.GetSection(childSectionName);
                    children = ProcessSection <PipelineItemChildType, object>(
                        childrenSection,
                        healthReporter,
                        childFactories,
                        childFactories: null,       // Only one level of nexting is supported
                        childSectionName: null);

                    createdItems.Add(new ItemWithChildren <PipelineItemType, PipelineItemChildType>(item, children.Select(c => c.Item).ToList()));
                }
                else
                {
                    createdItems.Add(new ItemWithChildren <PipelineItemType, PipelineItemChildType>(item, null));
                }
            }

            return(createdItems);
        }
Beispiel #12
0
 public HealthController(IHealthReporter healthReporter)
 {
     this.healthReporter = healthReporter;
 }
Beispiel #13
0
        private void Initialize(IReadOnlyCollection <EventSourceConfiguration> eventSources, IHealthReporter healthReporter)
        {
            this.healthReporter = healthReporter;
            this.subject        = new EventFlowSubject <EventData>();

            this.EventSources = eventSources;
            if (this.EventSources.Count() == 0)
            {
                healthReporter.ReportWarning($"{nameof(EventSourceInput)}: no event sources configured", nameof(EventSourceInput));
                return;
            }

            lock (this)  // See OnEventSourceCreated() for explanation why we are locking on 'this' here.
            {
                EnableInitialSources();
                this.constructed = true;
            }
        }
        public LoggerInput CreateItem(IConfiguration configuration, IHealthReporter healthReporter)
        {
            Validation.Requires.NotNull(healthReporter, nameof(healthReporter));

            return(new LoggerInput(healthReporter));
        }
Beispiel #15
0
 public UpdateAppDomainName CreateItem(IConfiguration configuration, IHealthReporter healthReporter)
 {
     return(new UpdateAppDomainName());
 }
        public ApplicationInsightsOutput(ApplicationInsightsOutputConfiguration applicationInsightsOutputConfiguration, IHealthReporter healthReporter)
        {
            Requires.NotNull(applicationInsightsOutputConfiguration, nameof(applicationInsightsOutputConfiguration));
            Requires.NotNull(healthReporter, nameof(healthReporter));

            this.healthReporter = healthReporter;
            Initialize(applicationInsightsOutputConfiguration);
        }
        public static void AddPayloadProperty(IDictionary <string, object> payload, string key, object value, IHealthReporter healthReporter, string context)
        {
            Requires.NotNull(payload, nameof(payload));
            Requires.NotNull(key, nameof(key));
            Requires.NotNull(healthReporter, nameof(healthReporter));

            if (!payload.ContainsKey(key))
            {
                payload.Add(key, value);
                return;
            }

            string newKey;
            int    i = 1;

            //update property key till there is no such key in dict
            do
            {
                newKey = key + "_" + i.ToString("d");
                i++;
            }while (payload.ContainsKey(newKey));

            payload.Add(newKey, value);
            healthReporter.ReportWarning($"The property with the key '{key}' already exist in the event payload. Value was added under key '{newKey}'", context);
        }
Beispiel #18
0
 public EtwInputConfigurationPatch(IConfiguration configuration, IHealthReporter healthReporter)
     : base(configuration, healthReporter)
 {
 }
Beispiel #19
0
        public EventSourceInput(IReadOnlyCollection <EventSourceConfiguration> eventSources, IHealthReporter healthReporter)
        {
            Requires.NotNull(eventSources, nameof(eventSources));
            Requires.NotNull(healthReporter, nameof(healthReporter));

            Initialize(eventSources, healthReporter);
        }
Beispiel #20
0
        internal static IConfigurationRoot ApplyFabricConfigurationOverrides(
            this IConfigurationRoot configurationRoot,
            string configPackagePath,
            IHealthReporter healthReporter)
        {
            Debug.Assert(configurationRoot != null);
            Debug.Assert(!string.IsNullOrWhiteSpace(configPackagePath));
            Debug.Assert(healthReporter != null);

            Regex fabricValueReferenceRegex = new Regex(FabricConfigurationValueReference, RegexOptions.CultureInvariant, TimeSpan.FromMilliseconds(100));
            Regex fabricFileReferenceRegex  = new Regex(FabricConfigurationFileReference, RegexOptions.CultureInvariant, TimeSpan.FromMilliseconds(100));

            // Use ToList() to ensure that configuration is fully enumerated before starting to modify it.
            foreach (var kvp in configurationRoot.AsEnumerable().ToList())
            {
                if (kvp.Value == null)
                {
                    continue;
                }

                try
                {
                    Match valueReferenceMatch = fabricValueReferenceRegex.Match(kvp.Value);
                    if (valueReferenceMatch.Success)
                    {
                        string valueReferencePath = ConfigurationPath.Combine(valueReferenceMatch.Groups["section"].Value, valueReferenceMatch.Groups["name"].Value);
                        string newValue           = configurationRoot[valueReferencePath];
                        if (string.IsNullOrEmpty(newValue))
                        {
                            healthReporter.ReportWarning(
                                $"Configuration value reference '{kvp.Value}' was encountered but no corresponding configuration value was found using path '{valueReferencePath}'",
                                EventFlowContextIdentifiers.Configuration);
                        }
                        else
                        {
                            configurationRoot[kvp.Key] = newValue;
                        }
                    }

                    Match fileReferenceMatch = fabricFileReferenceRegex.Match(kvp.Value);
                    if (fileReferenceMatch.Success)
                    {
                        string configFileName = fileReferenceMatch.Groups["filename"].Value;
                        if (string.IsNullOrWhiteSpace(configFileName))
                        {
                            healthReporter.ReportWarning(
                                $"Configuration file reference '{kvp.Value}' was encountered but the file name part is missing",
                                EventFlowContextIdentifiers.Configuration);
                        }
                        else
                        {
                            string configFilePath = Path.Combine(configPackagePath, configFileName);
                            configurationRoot[kvp.Key] = configFilePath;
                        }
                    }
                }
                catch (RegexMatchTimeoutException)
                {
                    healthReporter.ReportWarning(
                        $"Configuration entry with key '{kvp.Key}' and value '{kvp.Value}' could not be checked if it represents a configuration value reference--a timeout occurred when the value was being parsed.",
                        EventFlowContextIdentifiers.Configuration);
                    continue;
                }
            }

            return(configurationRoot);
        }
Beispiel #21
0
        public static EventData ToEventData(this EventWrittenEventArgs eventSourceEvent, IHealthReporter healthReporter, string context)
        {
            Debug.Assert(healthReporter != null);

            EventData eventData = new EventData
            {
                ProviderName = eventSourceEvent.EventSource.Name,
                Timestamp    = DateTimePrecise.UtcNow,
                Level        = (LogLevel)(int)eventSourceEvent.Level,
                Keywords     = (long)eventSourceEvent.Keywords
            };

            IDictionary <string, object> payloadData = eventData.Payload;

            payloadData.Add(nameof(eventSourceEvent.EventId), eventSourceEvent.EventId);
            payloadData.Add(nameof(eventSourceEvent.EventName), eventSourceEvent.EventName);
            if (eventSourceEvent.ActivityId != default(Guid))
            {
                payloadData.Add(nameof(EventWrittenEventArgs.ActivityId), ActivityPathDecoder.GetActivityPathString(eventSourceEvent.ActivityId));
            }
            if (eventSourceEvent.RelatedActivityId != default(Guid))
            {
                payloadData.Add(nameof(EventWrittenEventArgs.RelatedActivityId), ActivityPathDecoder.GetActivityPathString(eventSourceEvent.RelatedActivityId));
            }

            try
            {
                if (eventSourceEvent.Message != null)
                {
                    // If the event has a badly formatted manifest, the FormattedMessage property getter might throw
                    payloadData.Add(nameof(eventSourceEvent.Message), string.Format(CultureInfo.InvariantCulture, eventSourceEvent.Message, eventSourceEvent.Payload.ToArray()));
                }
            }
            catch { }

            eventSourceEvent.ExtractPayloadData(eventData, healthReporter, context);

            return(eventData);
        }
Beispiel #22
0
        public DiagnosticPipeline(
            IHealthReporter healthReporter,
            IReadOnlyCollection <IObservable <EventData> > inputs,
            IReadOnlyCollection <IFilter> globalFilters,
            IReadOnlyCollection <EventSink> sinks,
            DiagnosticPipelineConfiguration pipelineConfiguration = null,
            bool disposeDependencies = false)
        {
            Requires.NotNull(healthReporter, nameof(healthReporter));
            Requires.NotNull(inputs, nameof(inputs));
            Requires.Argument(inputs.Count > 0, nameof(inputs), "There must be at least one input");
            Requires.NotNull(sinks, nameof(sinks));
            Requires.Argument(sinks.Count > 0, nameof(sinks), "There must be at least one sink");

            this.eventsInProgress = 0;

            this.pipelineConfiguration = pipelineConfiguration ?? new DiagnosticPipelineConfiguration();

            // An estimatie how many batches of events to allow inside the pipeline.
            // We want to be able to process full buffer of events, but also have enough batches in play in case of high concurrency.
            int MaxNumberOfBatchesInProgress = Math.Max(
                5 * this.pipelineConfiguration.MaxConcurrency,
                this.pipelineConfiguration.PipelineBufferSize / this.pipelineConfiguration.MaxEventBatchSize);

            this.Inputs = inputs;
            this.Sinks  = sinks;

            // Just play nice and make sure there is always something to enumerate on
            this.GlobalFilters = globalFilters ?? new IFilter[0];

            this.HealthReporter          = healthReporter;
            this.cancellationTokenSource = new CancellationTokenSource();
            var propagateCompletion = new DataflowLinkOptions()
            {
                PropagateCompletion = true
            };

            this.pipelineLinkDisposables = new List <IDisposable>();
            this.pipelineCompletionTasks = new List <Task>();

            var inputBuffer = new BufferBlock <EventData>(
                new DataflowBlockOptions()
            {
                BoundedCapacity   = this.pipelineConfiguration.PipelineBufferSize,
                CancellationToken = this.cancellationTokenSource.Token
            });

            this.pipelineHead = inputBuffer;
            this.pipelineCompletionTasks.Add(inputBuffer.Completion);

            var batcher = new BatchBlock <EventData>(
                this.pipelineConfiguration.MaxEventBatchSize,
                new GroupingDataflowBlockOptions()
            {
                BoundedCapacity   = this.pipelineConfiguration.MaxEventBatchSize,
                CancellationToken = this.cancellationTokenSource.Token
            }
                );

            this.pipelineLinkDisposables.Add(inputBuffer.LinkTo(batcher, propagateCompletion));
            this.pipelineCompletionTasks.Add(batcher.Completion);

            this.pipelineLinkDisposables.Add(new Timer(
                                                 (unused) => batcher.TriggerBatch(),
                                                 state: null,
                                                 dueTime: TimeSpan.FromMilliseconds(this.pipelineConfiguration.MaxBatchDelayMsec),
                                                 period: TimeSpan.FromMilliseconds(this.pipelineConfiguration.MaxBatchDelayMsec)));

            ISourceBlock <EventData[]> sinkSource;
            FilterAction filterTransform;

            if (this.GlobalFilters.Count > 0)
            {
                filterTransform = new FilterAction(
                    this.GlobalFilters,
                    this.cancellationTokenSource.Token,
                    this.pipelineConfiguration.MaxEventBatchSize,
                    this.pipelineConfiguration.MaxConcurrency,
                    healthReporter,
                    this.OnEventsFilteredOut);
                var globalFiltersBlock = filterTransform.GetFilterBlock();
                this.pipelineLinkDisposables.Add(batcher.LinkTo(globalFiltersBlock, propagateCompletion));
                this.pipelineCompletionTasks.Add(globalFiltersBlock.Completion);
                sinkSource = globalFiltersBlock;
            }
            else
            {
                sinkSource = batcher;
            }

            if (sinks.Count > 1)
            {
                // After broadcasting we will effectively have (sinks.Count - 1) * batch.Length more events in the pipeline,
                // because the broadcaster is cloning the events for the sake of each sink (filters-output combination).
                var eventCounter = new TransformBlock <EventData[], EventData[]>(
                    (batch) => { Interlocked.Add(ref this.eventsInProgress, (sinks.Count - 1) * batch.Length);  return(batch); },
                    new ExecutionDataflowBlockOptions()
                {
                    BoundedCapacity   = MaxNumberOfBatchesInProgress,
                    CancellationToken = this.cancellationTokenSource.Token
                });
                this.pipelineLinkDisposables.Add(sinkSource.LinkTo(eventCounter, propagateCompletion));
                this.pipelineCompletionTasks.Add(eventCounter.Completion);

                var broadcaster = new BroadcastBlock <EventData[]>(
                    (events) => events?.Select((e) => e.DeepClone()).ToArray(),
                    new DataflowBlockOptions()
                {
                    BoundedCapacity   = MaxNumberOfBatchesInProgress,
                    CancellationToken = this.cancellationTokenSource.Token
                });
                this.pipelineLinkDisposables.Add(eventCounter.LinkTo(broadcaster, propagateCompletion));
                this.pipelineCompletionTasks.Add(broadcaster.Completion);
                sinkSource = broadcaster;
            }

            foreach (var sink in sinks)
            {
                ISourceBlock <EventData[]> outputSource = sinkSource;
                if (sink.Filters != null && sink.Filters.Count > 0)
                {
                    filterTransform = new FilterAction(
                        sink.Filters,
                        this.cancellationTokenSource.Token,
                        MaxNumberOfBatchesInProgress,
                        this.pipelineConfiguration.MaxConcurrency,
                        healthReporter,
                        this.OnEventsFilteredOut);
                    var filterBlock = filterTransform.GetFilterBlock();
                    this.pipelineLinkDisposables.Add(sinkSource.LinkTo(filterBlock, propagateCompletion));
                    this.pipelineCompletionTasks.Add(filterBlock.Completion);
                    outputSource = filterBlock;
                }

                OutputAction outputAction = new OutputAction(
                    sink.Output,
                    this.cancellationTokenSource.Token,
                    MaxNumberOfBatchesInProgress,
                    this.pipelineConfiguration.MaxConcurrency,
                    healthReporter,
                    (eventsSentCount) => Interlocked.Add(ref this.eventsInProgress, -eventsSentCount));
                var outputBlock = outputAction.GetOutputBlock();
                this.pipelineLinkDisposables.Add(outputSource.LinkTo(outputBlock, propagateCompletion));
                this.pipelineCompletionTasks.Add(outputBlock.Completion);
            }

            IObserver <EventData> inputBufferObserver = new TargetBlockObserver <EventData>(
                inputBuffer,
                this.HealthReporter,
                () => Interlocked.Increment(ref this.eventsInProgress));

            this.inputSubscriptions = new List <IDisposable>(inputs.Count);
            foreach (var input in inputs)
            {
                this.inputSubscriptions.Add(input.Subscribe(inputBufferObserver));
            }

            this.disposed            = false;
            this.disposeDependencies = disposeDependencies;
        }
Beispiel #23
0
        private static void ExtractPayloadData(this EventWrittenEventArgs eventSourceEvent, EventData eventData, IHealthReporter healthReporter, string context)
        {
            if (eventSourceEvent.Payload == null || eventSourceEvent.PayloadNames == null)
            {
                return;
            }

            bool isEventCountersEvent = eventSourceEvent.EventName == "EventCounters" && eventSourceEvent.Payload.Count == 1 && eventSourceEvent.PayloadNames[0] == "Payload";

            if (isEventCountersEvent)
            {
                ExtractEventCounterPayloadData(eventSourceEvent, eventData, healthReporter, context);
            }
            else
            {
                ExtractEventPayloadData(eventSourceEvent, eventData, healthReporter, context);
            }
        }
Beispiel #24
0
        private static void ReportInvalidPipelineConfiguration(IHealthReporter healthReporter)
        {
            var errMsg = $"{nameof(DiagnosticPipelineFactory)}: pipeline settings configuration section is invalid--will use default settings for the diagnostic pipeline";

            healthReporter.ReportWarning(errMsg);
        }
Beispiel #25
0
        private static void ExtractEventPayloadData(this EventWrittenEventArgs eventSourceEvent, EventData eventData, IHealthReporter healthReporter, string context)
        {
            IEnumerator <object> payloadEnumerator       = eventSourceEvent.Payload.GetEnumerator();
            IEnumerator <string> payloadNamesEnunmerator = eventSourceEvent.PayloadNames.GetEnumerator();

            while (payloadEnumerator.MoveNext())
            {
                payloadNamesEnunmerator.MoveNext();
                eventData.AddPayloadProperty(payloadNamesEnunmerator.Current, payloadEnumerator.Current, healthReporter, context);
            }
        }
Beispiel #26
0
        public static DiagnosticPipeline CreatePipeline(IConfiguration configuration, IHealthReporter healthReporter = null)
        {
            Requires.NotNull(configuration, nameof(configuration));

            if (healthReporter == null)
            {
                healthReporter = CreateHealthReporter(configuration);
            }
            Verify.Operation(healthReporter != null, $"An instance of a health reporter could not be created and none was provider as a parameter to {nameof(CreatePipeline)} method");
            (healthReporter as IRequireActivation)?.Activate();

            IDictionary <string, string> inputFactories;
            IDictionary <string, string> outputFactories;
            IDictionary <string, string> filterFactories;

            CreateItemFactories(configuration, healthReporter, out inputFactories, out outputFactories, out filterFactories);

            // Step 1: instantiate inputs
            IConfigurationSection inputConfigurationSection = configuration.GetSection("inputs");

            if (inputConfigurationSection.GetChildren().Count() == 0)
            {
                ReportSectionEmptyAndThrow(healthReporter, inputConfigurationSection);
            }

            List <ItemWithChildren <IObservable <EventData>, object> > inputCreationResult;

            inputCreationResult = ProcessSection <IObservable <EventData>, object>(
                inputConfigurationSection,
                healthReporter,
                inputFactories,
                childFactories: null,
                childSectionName: null);

            List <IObservable <EventData> > inputs = inputCreationResult.Select(item => item.Item).ToList();

            if (inputs.Count == 0)
            {
                ReportNoItemsCreatedAndThrow(healthReporter, inputConfigurationSection);
            }

            try
            {
                // Step 2: instantiate global filters (if any)
                IConfigurationSection globalFilterConfigurationSection = configuration.GetSection("filters");
                List <ItemWithChildren <IFilter, object> > globalFilterCreationResult;

                // It completely fine to have a pipeline with no globals filters section, or an empty one
                globalFilterCreationResult = ProcessSection <IFilter, object>(
                    globalFilterConfigurationSection,
                    healthReporter,
                    filterFactories,
                    childFactories: null,
                    childSectionName: null);
                List <IFilter> globalFilters = globalFilterCreationResult.Select(item => item.Item).ToList();


                // Step 3: instantiate outputs
                IConfigurationSection outputConfigurationSection = configuration.GetSection("outputs");
                if (outputConfigurationSection.GetChildren().Count() == 0)
                {
                    ReportSectionEmptyAndThrow(healthReporter, outputConfigurationSection);
                }

                List <ItemWithChildren <IOutput, IFilter> > outputCreationResult;
                outputCreationResult = ProcessSection <IOutput, IFilter>(
                    outputConfigurationSection,
                    healthReporter,
                    outputFactories,
                    filterFactories,
                    childSectionName: "filters");

                List <IOutput> outputs = outputCreationResult.Select(item => item.Item).ToList();
                if (outputs.Count == 0)
                {
                    ReportNoItemsCreatedAndThrow(healthReporter, outputConfigurationSection);
                }

                // Step 4: assemble and return the pipeline
                IReadOnlyCollection <EventSink> sinks = outputCreationResult.Select(outputResult =>
                                                                                    new EventSink(outputResult.Item, outputResult.Children)
                                                                                    ).ToList();


                var pipelineSettings = new DiagnosticPipelineConfiguration();
                IConfigurationSection settingsConfigurationSection = configuration.GetSection("settings");
                try
                {
                    if (settingsConfigurationSection.GetChildren().Count() != 0)
                    {
                        settingsConfigurationSection.Bind(pipelineSettings);
                    }
                }
                catch
                {
                    ReportInvalidPipelineConfiguration(healthReporter);
                }

                DiagnosticPipeline pipeline = new DiagnosticPipeline(healthReporter, inputs, globalFilters, sinks, pipelineSettings, disposeDependencies: true);

                // Now the pipeline has assumed ownership of the inputs, setting inputs variable back to null so we won't
                // incorrectly dispose it in the finally block
                inputs = null;
                return(pipeline);
            }
            finally
            {
                DisposeOf(inputs);
            }
        }
Beispiel #27
0
        public DiagnosticPipeline(
            IHealthReporter healthReporter,
            IReadOnlyCollection <IObservable <EventData> > inputs,
            IReadOnlyCollection <IFilter> globalFilters,
            IReadOnlyCollection <EventSink> sinks,
            DiagnosticPipelineConfiguration pipelineConfiguration = null,
            bool disposeDependencies = false)
        {
            Requires.NotNull(healthReporter, nameof(healthReporter));
            Requires.NotNull(inputs, nameof(inputs));
            Requires.Argument(inputs.Count > 0, nameof(inputs), "There must be at least one input");
            Requires.NotNull(sinks, nameof(sinks));
            Requires.Argument(sinks.Count > 0, nameof(sinks), "There must be at least one sink");

            this.pipelineConfiguration = pipelineConfiguration ?? new DiagnosticPipelineConfiguration();

            this.Inputs = inputs;
            this.Sinks  = sinks;
            // Just play nice and make sure there is always something to enumerate on
            this.GlobalFilters           = globalFilters ?? new IFilter[0];
            this.HealthReporter          = healthReporter;
            this.cancellationTokenSource = new CancellationTokenSource();
            var propagateCompletion = new DataflowLinkOptions()
            {
                PropagateCompletion = true
            };

            this.pipelineDisposables = new List <IDisposable>();

            var inputBuffer = new BufferBlock <EventData>(
                new DataflowBlockOptions()
            {
                BoundedCapacity   = this.pipelineConfiguration.PipelineBufferSize,
                CancellationToken = this.cancellationTokenSource.Token
            });

            this.pipelineHead = inputBuffer;

            var batcher = new BatchBlock <EventData>(
                this.pipelineConfiguration.MaxEventBatchSize,
                new GroupingDataflowBlockOptions()
            {
                BoundedCapacity   = this.pipelineConfiguration.MaxEventBatchSize,
                CancellationToken = this.cancellationTokenSource.Token
            }
                );

            this.pipelineDisposables.Add(inputBuffer.LinkTo(batcher, propagateCompletion));

            this.pipelineDisposables.Add(new Timer(
                                             (unused) => batcher.TriggerBatch(),
                                             state: null,
                                             dueTime: TimeSpan.FromMilliseconds(this.pipelineConfiguration.MaxBatchDelayMsec),
                                             period: TimeSpan.FromMilliseconds(this.pipelineConfiguration.MaxBatchDelayMsec)));

            ISourceBlock <EventData[]> sinkSource;
            FilterAction filterTransform;

            if (this.GlobalFilters.Count > 0)
            {
                filterTransform = new FilterAction(
                    this.GlobalFilters,
                    this.cancellationTokenSource.Token,
                    this.pipelineConfiguration.MaxEventBatchSize,
                    this.pipelineConfiguration.MaxConcurrency,
                    healthReporter);
                var globalFiltersBlock = filterTransform.GetFilterBlock();
                this.pipelineDisposables.Add(batcher.LinkTo(globalFiltersBlock, propagateCompletion));
                sinkSource = globalFiltersBlock;
            }
            else
            {
                sinkSource = batcher;
            }

            if (sinks.Count > 1)
            {
                var broadcaster = new BroadcastBlock <EventData[]>(
                    (events) => events?.Select((e) => e.DeepClone()).ToArray(),
                    new DataflowBlockOptions()
                {
                    BoundedCapacity   = this.pipelineConfiguration.MaxEventBatchSize,
                    CancellationToken = this.cancellationTokenSource.Token
                });
                this.pipelineDisposables.Add(sinkSource.LinkTo(broadcaster, propagateCompletion));
                sinkSource = broadcaster;
            }

            foreach (var sink in sinks)
            {
                ISourceBlock <EventData[]> outputSource = sinkSource;
                if (sink.Filters != null && sink.Filters.Count > 0)
                {
                    filterTransform = new FilterAction(
                        sink.Filters,
                        this.cancellationTokenSource.Token,
                        this.pipelineConfiguration.MaxEventBatchSize,
                        this.pipelineConfiguration.MaxConcurrency,
                        healthReporter);
                    var filterBlock = filterTransform.GetFilterBlock();
                    this.pipelineDisposables.Add(sinkSource.LinkTo(filterBlock, propagateCompletion));
                    outputSource = filterBlock;
                }

                OutputAction outputAction = new OutputAction(
                    sink.Output,
                    this.cancellationTokenSource.Token,
                    this.pipelineConfiguration.MaxEventBatchSize,
                    this.pipelineConfiguration.MaxConcurrency,
                    healthReporter);
                ActionBlock <EventData[]> outputBlock = outputAction.GetOutputBlock();
                this.pipelineDisposables.Add(outputSource.LinkTo(outputBlock, propagateCompletion));
            }

            IObserver <EventData> inputBufferObserver = new TargetBlockObserver <EventData>(inputBuffer, this.HealthReporter);

            this.inputSubscriptions = new List <IDisposable>(inputs.Count);
            foreach (var input in inputs)
            {
                this.inputSubscriptions.Add(input.Subscribe(inputBufferObserver));
            }

            this.disposed            = false;
            this.disposeDependencies = disposeDependencies;
        }
Beispiel #28
0
        private void Initialize(IReadOnlyCollection <EtwProviderConfiguration> providers, IHealthReporter healthReporter)
        {
            this.healthReporter = healthReporter;
            this.subject        = new EventFlowSubject <EventData>();
            this.isDisposed     = false;
            this.SessionFactory = () => new StandardTraceEventSession(healthReporter);

            this.Providers = providers;
            // The session is not started until Activate() is called.
        }
Beispiel #29
0
 // Test constructor
 internal StdOutput(IHealthReporter healthReporter, Action <string> outputWriter) : this(healthReporter)
 {
     Requires.NotNull(outputWriter, nameof(outputWriter));
     this.writeOutput = outputWriter;
 }
        public PerformanceCounterInput(PerformanceCounterInputConfiguration configuration, IHealthReporter healthReporter)
        {
            Requires.NotNull(configuration, nameof(configuration));
            Requires.NotNull(healthReporter, nameof(healthReporter));

            Initialize(configuration, healthReporter);
        }
Beispiel #31
0
        public static EventData ToEventData(this EventWrittenEventArgs eventSourceEvent, IHealthReporter healthReporter, string context)
        {
            Debug.Assert(healthReporter != null);

            EventData eventData = new EventData
            {
                ProviderName = eventSourceEvent.EventSource.Name,
                Timestamp    = DateTime.UtcNow,
                Level        = (LogLevel)(int)eventSourceEvent.Level,
                Keywords     = (long)eventSourceEvent.Keywords
            };

            eventSourceEvent.ExtractPayloadData(eventData);

            eventData.AddPayloadProperty("EventId", eventSourceEvent.EventId, healthReporter, context);
            eventData.AddPayloadProperty("EventName", eventSourceEvent.EventName, healthReporter, context);
            eventData.AddPayloadProperty("ActivityID", ActivityPathString(eventSourceEvent.ActivityId), healthReporter, context);
            try
            {
                if (eventSourceEvent.Message != null)
                {
                    // If the event has a badly formatted manifest, the FormattedMessage property getter might throw
                    eventData.AddPayloadProperty("Message",
                                                 string.Format(CultureInfo.InvariantCulture, eventSourceEvent.Message, eventSourceEvent.Payload.ToArray()),
                                                 healthReporter,
                                                 context);
                }
            }
            catch { }

            return(eventData);
        }
Beispiel #32
0
 private static void ExtractEventCounterPayloadData(this EventWrittenEventArgs eventSourceEvent, EventData eventData, IHealthReporter healthReporter, string context)
 {
     foreach (var payload in (IDictionary <string, object>)eventSourceEvent.Payload[0])
     {
         eventData.AddPayloadProperty(payload.Key, payload.Value, healthReporter, context);
         eventData.SetMetadata(CreateMetricMetadata(payload.Key));
     }
 }
Beispiel #33
0
        public TableStorageEventListener(IConfigurationProvider configurationProvider, IHealthReporter healthReporter)
            : base(configurationProvider, healthReporter)
        {
            if (this.Disabled)
            {
                return;
            }

            Debug.Assert(configurationProvider != null);
            this.CreateTableClient(configurationProvider);

            Random randomNumberGenerator = new Random();

            this.instanceId = randomNumberGenerator.Next(100000000).ToString("D8");

            this.nextEntityId        = 0;
            this.identityIdResetLock = new object();

            this.Sender = new ConcurrentEventSender <EventData>(
                eventBufferSize: 1000,
                maxConcurrency: MaxConcurrentPartitions,
                batchSize: 50,
                noEventsDelay: TimeSpan.FromMilliseconds(1000),
                transmitterProc: this.SendEventsAsync,
                healthReporter: healthReporter);
        }
        public ElasticSearchOutput(ElasticSearchOutputConfiguration elasticSearchOutputConfiguration, IHealthReporter healthReporter)
        {
            Requires.NotNull(elasticSearchOutputConfiguration, nameof(elasticSearchOutputConfiguration));
            Requires.NotNull(healthReporter, nameof(healthReporter));

            this.healthReporter = healthReporter;

            // Clone the configuration instance since we are going to hold onto it (via this.connectionData)
            Initialize(elasticSearchOutputConfiguration.DeepClone());
        }
Beispiel #35
0
 public UnitTestFilter CreateItem(IConfiguration configuration, IHealthReporter healthReporter)
 {
     return(new UnitTestFilter());
 }