コード例 #1
0
        public void Should_merge_global_tags_when_key_values_provided_that_match_an_existing_tag()
        {
            // Arrange
            var builder       = new MetricsBuilder();
            var keyValuePairs = new Dictionary <string, string>
            {
                { "MetricsOptions:GlobalTags:tag1", "replaced" },
                { "MetricsOptions:GlobalTags:tag2", "added" }
            };
            var configuration = new ConfigurationBuilder().AddInMemoryCollection(keyValuePairs).Build();
            var options       = new MetricsOptions();

            options.GlobalTags.Add("tag1", "value1");

            // Act
            builder.Configuration.Configure(o => o.GlobalTags.Add("tag1", "value1"));
            builder.Configuration.ReadFrom(configuration);
            var metrics = builder.Build();

            // Assert
            metrics.Options.GlobalTags.Count.Should().Be(2);

            var tag1 = metrics.Options.GlobalTags.FirstOrDefault(t => t.Key == "tag1");

            tag1.Should().NotBeNull();
            tag1.Value.Should().Be("replaced");

            var tag2 = metrics.Options.GlobalTags.FirstOrDefault(t => t.Key == "tag2");

            tag2.Should().NotBeNull();
            tag2.Value.Should().Be("added");
        }
コード例 #2
0
        public void Can_set_global_tags_on_metric_options()
        {
            // Arrange
            var environmentBuilder = new EnvironmentInfoProvider();
            var environmentInfo    = environmentBuilder.Build();
            var expected           = new GlobalMetricTags(
                new Dictionary <string, string>
            {
                { "machine_name", environmentInfo.MachineName },
                { "app_name", environmentInfo.EntryAssemblyName },
                { "app_version", environmentInfo.EntryAssemblyVersion }
            });
            var options = new MetricsOptions();

            // Act
            options.WithGlobalTags(
                (globalTags, envInfo) =>
            {
                globalTags.Add("machine_name", envInfo.MachineName);
                globalTags.Add("app_name", envInfo.EntryAssemblyName);
                globalTags.Add("app_version", envInfo.EntryAssemblyVersion);
            });

            // Assert
            options.GlobalTags.Should().Equal(expected);
        }
コード例 #3
0
        static ProbeContext BuildProbes(FeatureConfigurationContext context, MetricsOptions options)
        {
            var durationBuilders = new DurationProbeBuilder[]
            {
                new CriticalTimeProbeBuilder(context),
                new ProcessingTimeProbeBuilder(context)
            };

            var performanceDiagnosticsBehavior = new ReceivePerformanceDiagnosticsBehavior();

            context.Pipeline.Register(
                "NServiceBus.Metrics.ReceivePerformanceDiagnosticsBehavior",
                performanceDiagnosticsBehavior,
                "Provides various performance counters for receive statistics"
                );

            var signalBuilders = new SignalProbeBuilder[]
            {
                new MessagePulledFromQueueProbeBuilder(performanceDiagnosticsBehavior),
                new MessageProcessingFailureProbeBuilder(performanceDiagnosticsBehavior),
                new MessageProcessingSuccessProbeBuilder(performanceDiagnosticsBehavior),
                new RetriesProbeBuilder(options)
            };

            return(new ProbeContext(
                       durationBuilders.Select(b => b.Build()).ToArray(),
                       signalBuilders.Select(b => b.Build()).ToArray()
                       ));
        }
コード例 #4
0
 public MessagingProfileMetricsDetailServiceTest(MockHttpClientFixture mockHttpClientFixture)
     : base(mockHttpClientFixture)
 {
     metricsOptions = null;
     requestOptions = null;
     service        = new MessagingProfileMetricsDetailService();
 }
コード例 #5
0
        public void Poll_GeneratesExpectedEvents()
        {
            var source   = new CLRRuntimeSource();
            var listener = source.Source as DiagnosticListener;

            var options  = new MetricsOptions();
            var stats    = new OpenCensusStats();
            var tags     = new OpenCensusTags();
            var observer = new TestObserver(options, stats, tags, null);

            listener.Subscribe(observer);

            source.Poll();

            Assert.Equal(2, observer.Events.Count);
            Assert.Equal(2, observer.Args.Count);

            Assert.Equal(CLRRuntimeSource.HEAP_EVENT, observer.Events[0]);
            Assert.Equal(CLRRuntimeSource.THREADS_EVENT, observer.Events[1]);

            var heapMetrics = (CLRRuntimeSource.HeapMetrics)observer.Args[0];

            Assert.NotEqual(0, heapMetrics.TotalMemory);
            Assert.NotNull(heapMetrics.CollectionCounts);
            Assert.NotEqual(0, heapMetrics.CollectionCounts.Count);

            var threadMetrics = (CLRRuntimeSource.ThreadMetrics)observer.Args[1];

            Assert.NotEqual(0, threadMetrics.AvailableThreadCompletionPort);
            Assert.NotEqual(0, threadMetrics.AvailableThreadPoolWorkers);
            Assert.NotEqual(0, threadMetrics.MaxThreadCompletionPort);
            Assert.NotEqual(0, threadMetrics.MaxThreadPoolWorkers);
        }
コード例 #6
0
        public MetricsService(IOptions <MetricsOptions> options, ILogger <MetricsService> logger) : base(logger)
        {
            var hostname = options.Value.Hostname;

            if (hostname == "0.0.0.0" || string.IsNullOrEmpty(hostname))
            {
                hostname = "+";
            }

            options.Value.Hostname = hostname;

            if (string.IsNullOrEmpty(options.Value.Endpoint))
            {
                options.Value.Endpoint = "metrics/";
            }

            if (options.Value.Port == default)
            {
                options.Value.Port = 8080;
            }

            this.m_options = options.Value;
            this.m_server  = new MetricServer(hostname, options.Value.Port, options.Value.Endpoint);
            this.m_logger  = logger;
        }
コード例 #7
0
        public void Can_override_option_instance_values_with_key_value_pair_options()
        {
            // Arrange
            var options = new MetricsOptions
            {
                Enabled             = true,
                DefaultContextLabel = "initial value",
                GlobalTags          = new GlobalMetricTags(new Dictionary <string, string> {
                    { "initial", "value" }
                })
            };

            var keyValuePairs = new Dictionary <string, string>
            {
                { "MetricsOptions:DefaultContextLabel", "Testing" },
                { "MetricsOptions:GlobalTags:tag1", "value1" },
                { "MetricsOptions:GlobalTags:tag2", "value2" },
                { "MetricsOptions:Enabled", "false" }
            };

            // Act
            var metrics = new MetricsBuilder().Configuration.Configure(options, keyValuePairs).Build();

            // Assert
            metrics.Options.DefaultContextLabel.Should().Be("Testing");
            metrics.Options.GlobalTags.Count.Should().Be(2);
            metrics.Options.GlobalTags.First().Key.Should().Be("tag1");
            metrics.Options.GlobalTags.First().Value.Should().Be("value1");
            metrics.Options.GlobalTags.Skip(1).First().Key.Should().Be("tag2");
            metrics.Options.GlobalTags.Skip(1).First().Value.Should().Be("value2");
            metrics.Options.Enabled.Should().BeFalse();
        }
コード例 #8
0
    private static MetricsWebHostOptions GetMetricsWebHostOptions(MetricsOptions metricsOptions)
    {
        var options = new MetricsWebHostOptions();

        if (!metricsOptions.Enabled)
        {
            return(options);
        }

        if (!metricsOptions.PrometheusEnabled)
        {
            return(options);
        }

        options.EndpointOptions = endpointOptions =>
        {
            switch (metricsOptions.PrometheusFormatter?.ToLowerInvariant() ?? string.Empty)
            {
            case "protobuf":
                endpointOptions.MetricsEndpointOutputFormatter =
                    new MetricsPrometheusProtobufOutputFormatter();
                break;

            default:
                endpointOptions.MetricsEndpointOutputFormatter =
                    new MetricsPrometheusTextOutputFormatter();
                break;
            }
        };

        return(options);
    }
コード例 #9
0
 public MessagingProfileMetricsServiceTests(MockHttpClientFixture mockHttpClientFixture)
     : base(mockHttpClientFixture)
 {
     service     = new MessagingProfileMetricsService();
     listOptions = null; //null due to mock not allowing params
     getOptions  = null; //null due to mock not allowing params
 }
コード例 #10
0
        public static IEnumerable <KeyValuePair <string, string> > ToKeyValue(this MetricsOptions options)
        {
            var result = new Dictionary <string, string>
            {
                [KeyValuePairMetricsOptions.DefaultContextLabelDirective] = options.DefaultContextLabel,
                [KeyValuePairMetricsOptions.EnabledDirective]             = options.Enabled.ToString()
            };

            foreach (var globalTag in options.GlobalTags)
            {
                var key = $"{KeyValuePairMetricsOptions.GlobalTagsDirective}:{globalTag.Key}";

                if (!result.ContainsKey(key))
                {
                    result.Add(key, globalTag.Value);
                }
            }

            foreach (var contextualTag in options.ContextualTags)
            {
                var key = $"{KeyValuePairMetricsOptions.ContextualTagsDirective}:{contextualTag.Key}";

                if (!result.ContainsKey(key))
                {
                    result.Add(key, "<computed>");
                }
            }

            return(result);
        }
        public void ParseTags_ReturnsExpected()
        {
            var opts  = new MetricsOptions();
            var stats = new OpenCensusStats();

            var ep     = new MetricsEndpoint(opts, stats);
            var middle = new MetricsEndpointOwinMiddleware(null, ep);

            var context1 = CreateRequest("GET", "/metrics/Foo.Bar.Class", "foo=key:value");
            var result   = middle.ParseTags(context1.Request.Query);

            Assert.NotNull(result);
            Assert.Empty(result);

            var context2 = CreateRequest("GET", "/metrics/Foo.Bar.Class", "tag=key:value");

            result = middle.ParseTags(context2.Request.Query);
            Assert.NotNull(result);
            Assert.Contains(new KeyValuePair <string, string>("key", "value"), result);

            var context3 = CreateRequest("GET", "/metrics/Foo.Bar.Class", "tag=key:value&foo=key:value&tag=key1:value1");

            result = middle.ParseTags(context3.Request.Query);
            Assert.NotNull(result);
            Assert.Contains(new KeyValuePair <string, string>("key", "value"), result);
            Assert.Contains(new KeyValuePair <string, string>("key1", "value1"), result);
            Assert.Equal(2, result.Count);

            var context4 = CreateRequest("GET", "/metrics/Foo.Bar.Class", "tag=key:value&foo=key:value&tag=key:value");

            result = middle.ParseTags(context4.Request.Query);
            Assert.NotNull(result);
            Assert.Contains(new KeyValuePair <string, string>("key", "value"), result);
            Assert.Single(result);
        }
コード例 #12
0
        public void HandleExceptionEvent_RecordsStats()
        {
            var options  = new MetricsOptions();
            var stats    = new OpenCensusStats();
            var tags     = new OpenCensusTags();
            var observer = new HttpClientCoreObserver(options, stats, tags, null);

            var req  = GetHttpRequestMessage();
            var resp = GetHttpResponseMessage(HttpStatusCode.InternalServerError);

            Activity act = new Activity("Test");

            act.Start();
            Thread.Sleep(1000);
            act.SetEndTime(DateTime.UtcNow);

            observer.HandleExceptionEvent(act, req);
            observer.HandleExceptionEvent(act, req);

            var reqData  = stats.ViewManager.GetView(ViewName.Create("http.client.requests"));
            var aggData1 = reqData.SumWithTags() as IDistributionData;

            Assert.InRange(aggData1.Mean, 995.0, 1005.0);
            Assert.InRange(aggData1.Max, 995.0, 1005.0);

            reqData = stats.ViewManager.GetView(ViewName.Create("http.client.requests.count"));
            var aggData2 = reqData.SumWithTags() as ISumDataLong;

            Assert.Equal(2, aggData2.Sum);

            act.Stop();
        }
コード例 #13
0
        public void Should_merge_global_tags_when_configured_more_than_once_key_values_provided()
        {
            // Arrange
            var options = new MetricsOptions();

            options.Enabled = true;
            options.GlobalTags.Add("tag1", "value1");
            options.DefaultContextLabel = "test";

            var options2 = new MetricsOptions();

            options2.Enabled = true;
            options2.GlobalTags.Add("tag2", "value2");
            options2.DefaultContextLabel = "test";

            // Act
            var metrics = new MetricsBuilder()
                          .Configuration.Configure(options)
                          .Configuration.Extend(options2.ToKeyValue())
                          .Build();

            // Assert
            metrics.Options.GlobalTags.Count.Should().Be(2);
            metrics.Options.GlobalTags.First().Key.Should().Be("tag1");
            metrics.Options.GlobalTags.First().Value.Should().Be("value1");
            metrics.Options.GlobalTags.Skip(1).First().Key.Should().Be("tag2");
            metrics.Options.GlobalTags.Skip(1).First().Value.Should().Be("value2");
        }
コード例 #14
0
        public void Constructor_BindsConfigurationCorrectly()
        {
            var appsettings = new Dictionary <string, string>()
            {
                ["management:endpoints:enabled"]                      = "false",
                ["management:endpoints:sensitive"]                    = "false",
                ["management:endpoints:path"]                         = "/management",
                ["management:endpoints:metrics:enabled"]              = "false",
                ["management:endpoints:metrics:sensitive"]            = "false",
                ["management:endpoints:metrics:id"]                   = "metricsmanagement",
                ["management:endpoints:metrics:ingressIgnorePattern"] = "pattern",
                ["management:endpoints:metrics:egressIgnorePattern"]  = "pattern",
            };
            ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();

            configurationBuilder.AddInMemoryCollection(appsettings);
            var config = configurationBuilder.Build();

            var opts = new MetricsOptions(config);

            Assert.False(opts.Enabled);
            Assert.False(opts.Sensitive);
            Assert.Equal("metricsmanagement", opts.Id);
            Assert.Equal("pattern", opts.IngressIgnorePattern);
            Assert.Equal("pattern", opts.EgressIgnorePattern);

            Assert.NotNull(opts.Global);
            Assert.False(opts.Global.Enabled);
            Assert.False(opts.Global.Sensitive);
            Assert.Equal("/management", opts.Global.Path);
        }
コード例 #15
0
        public void HandleStopEvent_RecordsStats()
        {
            var options  = new MetricsOptions();
            var stats    = new OpenCensusStats();
            var tags     = new OpenCensusTags();
            var observer = new AspNetCoreHostingObserver(options, stats, tags, null);

            var context = GetHttpRequestMessage();
            var exceptionHandlerFeature = new ExceptionHandlerFeature()
            {
                Error = new ArgumentNullException()
            };

            context.Features.Set <IExceptionHandlerFeature>(exceptionHandlerFeature);
            context.Response.StatusCode = 500;

            Activity act = new Activity("Test");

            act.Start();
            Thread.Sleep(1000);
            act.SetEndTime(DateTime.UtcNow);

            observer.HandleStopEvent(act, context);
            observer.HandleStopEvent(act, context);

            var reqData  = stats.ViewManager.GetView(ViewName.Create("http.server.request.time"));
            var aggData1 = reqData.SumWithTags() as IDistributionData;

            Assert.Equal(2, aggData1.Count);
            Assert.True(aggData1.Mean > 1000.00);
            Assert.True(aggData1.Max > 1000.00);

            act.Stop();
        }
コード例 #16
0
        public void Should_merge_global_tags_when_key_values_provided_that_match_an_existing_tag()
        {
            // Arrange
            var builder       = new MetricsBuilder();
            var configuration = new ConfigurationBuilder().AddJsonFile("JsonFIles/MetricsOptions.json").Build();
            var options       = new MetricsOptions();

            options.GlobalTags.Add("tag1", "value1");

            // Act
            builder.Configuration.Configure(options);
            builder.Configuration.ReadFrom(configuration);
            var metrics = builder.Build();

            // Assert
            metrics.Options.GlobalTags.Count.Should().Be(3);

            var tag1 = metrics.Options.GlobalTags.FirstOrDefault(t => t.Key == "tag1");

            tag1.Should().NotBeNull();
            tag1.Value.Should().Be("value1");

            var tag2 = metrics.Options.GlobalTags.FirstOrDefault(t => t.Key == "env");

            tag2.Should().NotBeNull();
            tag2.Value.Should().Be("stage");

            var tag3 = metrics.Options.GlobalTags.FirstOrDefault(t => t.Key == "tagkey");

            tag3.Should().NotBeNull();
            tag3.Value.Should().Be("tagValue");
        }
コード例 #17
0
        public void Invoke_WithNullMetricsRequest_ReturnsExpected()
        {
            var opts  = new MetricsOptions();
            var stats = new OpenCensusStats();

            SetupStats(stats);

            var ep     = new MetricsEndpoint(opts, stats);
            var result = ep.Invoke(null);

            Assert.NotNull(result);
            Assert.IsType <MetricsListNamesResponse>(result);
            MetricsListNamesResponse resp = result as MetricsListNamesResponse;

            Assert.NotEmpty(resp.Names);
            Assert.Contains("http.server.requests", resp.Names);
            Assert.Contains("jvm.memory.used", resp.Names);
            Assert.Equal(2, resp.Names.Count);

            opts  = new MetricsOptions();
            stats = new OpenCensusStats();

            ep     = new MetricsEndpoint(opts, stats);
            result = ep.Invoke(null);
            Assert.NotNull(result);

            Assert.IsType <MetricsListNamesResponse>(result);
            resp = result as MetricsListNamesResponse;
            Assert.Empty(resp.Names);
        }
コード例 #18
0
        public void CreateFromConfig()
        {
            _sut = MetricsOptions.CreateFromConfig();

            Assert.Equal(_sut.HostName, "localhost");
            Assert.Equal(_sut.Port, 8253);
        }
コード例 #19
0
 public DatadogFeature()
 {
     Defaults(settings =>
     {
         _metricsOptions = settings.EnableMetrics();
     });
     EnableByDefault();
 }
コード例 #20
0
        public void Constructor_InitializesWithDefaults()
        {
            var opts = new MetricsOptions();

            Assert.True(opts.Enabled);
            Assert.True(opts.Sensitive);
            Assert.Equal("metrics", opts.Id);
        }
コード例 #21
0
 public MetricsController(ILogger <MetricsController> logger,
                          IServiceProvider serviceProvider,
                          IOptions <MetricsOptions> metricsOptions)
 {
     _logger         = logger;
     _metricsStore   = serviceProvider.GetService <MetricsStoreService>();
     _metricsOptions = metricsOptions.Value;
 }
コード例 #22
0
 protected MetricsMiddlewareBase(MetricsOptions options)
 {
     if (options == null)
     {
         throw new ArgumentNullException(nameof(options));
     }
     _options = options;
 }
コード例 #23
0
ファイル: Startup.cs プロジェクト: kelltrick/dotnet-monitor
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // AddControllers is sufficient because the tool does not use Razor nor Views.
            services.AddControllers()
            .AddJsonOptions(options =>
            {
                // Allow serialization of enum values into strings rather than numbers.
                options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
            })
            .AddApplicationPart(typeof(DiagController).Assembly);

            services.AddControllers(options =>
            {
                options.Filters.Add(typeof(EgressValidationUnhandledExceptionFilter));
            });

            services.Configure <ApiBehaviorOptions>(options =>
            {
                options.InvalidModelStateResponseFactory = context =>
                {
                    var details = new ValidationProblemDetails(context.ModelState);
                    var result  = new BadRequestObjectResult(details);
                    result.ContentTypes.Add(ContentTypes.ApplicationProblemJson);
                    return(result);
                };
            });

            services.Configure <BrotliCompressionProviderOptions>(options =>
            {
                options.Level = CompressionLevel.Optimal;
            });

            services.AddResponseCompression(configureOptions =>
            {
                configureOptions.Providers.Add <BrotliCompressionProvider>();
                configureOptions.MimeTypes = new List <string> {
                    ContentTypes.ApplicationOctetStream
                };
            });

            // This is needed to allow the StreamingLogger to synchronously write to the output stream.
            // Eventually should switch StreamingLoggger to something that allows for async operations.
            services.Configure <KestrelServerOptions>(options =>
            {
                options.AllowSynchronousIO = true;
            });

            var metricsOptions = new MetricsOptions();

            Configuration.Bind(ConfigurationKeys.Metrics, metricsOptions);
            if (metricsOptions.Enabled.GetValueOrDefault(MetricsOptionsDefaults.Enabled))
            {
                services.AddSingleton <MetricsStoreService>();
                services.AddHostedService <MetricsService>();
            }

            services.AddSingleton <IMetricsPortsProvider, MetricsPortsProvider>();
        }
 private static void UseMetricsMiddleware <TMiddleware>(
     IApplicationBuilder app,
     MetricsOptions metricsOptions,
     IOptions <ResourceMetricsOptions> ResourceMiddlwareOptionsAccessor)
 {
     app.UseWhen(
         context => ShouldUseMetricsEndpoint(ResourceMiddlwareOptionsAccessor, metricsOptions, context),
         appBuilder => { appBuilder.UseMiddleware <TMiddleware>(); });
 }
コード例 #25
0
        private static void MetricsConfiger(MetricsOptions options)
        {
            var configer = Configuration.GetSection("MetricsOptions");


            options.AddAppTag(configer.GetValue <string>("DefaultContextLabel"));
            //options.AddEnvTag("Developer");
            //options.AddServerTag("LocationServer");
        }
コード例 #26
0
        public void Constructor_RegistersExpectedViews()
        {
            var options  = new MetricsOptions();
            var stats    = new OpenCensusStats();
            var tags     = new OpenCensusTags();
            var observer = new AspNetCoreHostingObserver(options, stats, tags, null);

            Assert.NotNull(stats.ViewManager.GetView(ViewName.Create("http.server.requests")));
        }
コード例 #27
0
        public void HandleThreadsEvent_RecordsValues()
        {
            var options  = new MetricsOptions();
            var stats    = new OpenCensusStats();
            var tags     = new OpenCensusTags();
            var observer = new CLRRuntimeObserver(options, stats, tags, null);

            CLRRuntimeSource.ThreadMetrics metrics = new CLRRuntimeSource.ThreadMetrics(100, 100, 200, 200);
            observer.HandleThreadsEvent(metrics);

            var live    = stats.ViewManager.GetView(ViewName.Create("clr.threadpool.active"));
            var aggData = live.SumWithTags() as IMeanData;

            Assert.Equal(100, aggData.Mean);
            Assert.Equal(100, aggData.Min);
            Assert.Equal(100, aggData.Max);

            aggData = live.SumWithTags(new List <ITagValue>()
            {
                TagValue.Create("worker")
            }) as IMeanData;
            Assert.Equal(100, aggData.Mean);
            Assert.Equal(100, aggData.Min);
            Assert.Equal(100, aggData.Max);

            aggData = live.SumWithTags(new List <ITagValue>()
            {
                TagValue.Create("completionPort")
            }) as IMeanData;
            Assert.Equal(100, aggData.Mean);
            Assert.Equal(100, aggData.Min);
            Assert.Equal(100, aggData.Max);

            var avail = stats.ViewManager.GetView(ViewName.Create("clr.threadpool.avail"));

            aggData = avail.SumWithTags() as IMeanData;
            Assert.Equal(100, aggData.Mean);
            Assert.Equal(100, aggData.Min);
            Assert.Equal(100, aggData.Max);

            aggData = avail.SumWithTags(new List <ITagValue>()
            {
                TagValue.Create("worker")
            }) as IMeanData;
            Assert.Equal(100, aggData.Mean);
            Assert.Equal(100, aggData.Min);
            Assert.Equal(100, aggData.Max);

            aggData = avail.SumWithTags(new List <ITagValue>()
            {
                TagValue.Create("completionPort")
            }) as IMeanData;
            Assert.Equal(100, aggData.Mean);
            Assert.Equal(100, aggData.Min);
            Assert.Equal(100, aggData.Max);
        }
コード例 #28
0
        public KeyValuePairMetricsOptions(MetricsOptions options, IEnumerable <KeyValuePair <string, string> > optionValues)
        {
            if (optionValues == null)
            {
                throw new ArgumentNullException(nameof(optionValues));
            }

            _options      = options;
            _optionValues = optionValues.ToDictionary(o => o.Key, o => o.Value);
        }
        public void Constructor_RegistersExpectedViews()
        {
            var options  = new MetricsOptions();
            var stats    = new OpenCensusStats();
            var tags     = new OpenCensusTags();
            var observer = new HttpClientDesktopObserver(options, stats, tags, null);

            Assert.NotNull(stats.ViewManager.GetView(ViewName.Create("http.desktop.client.request.time")));
            Assert.NotNull(stats.ViewManager.GetView(ViewName.Create("http.desktop.client.request.count")));
        }
 private static void UseMetricsMiddleware <TMiddleware>(
     IApplicationBuilder app,
     MetricsOptions metricsOptions,
     IOptions <MetricsWebTrackingOptions> trackingMiddlwareOptionsAccessor)
 {
     app.UseWhen(
         context => !IsNotAnIgnoredRoute(trackingMiddlwareOptionsAccessor.Value.IgnoredRoutesRegex, context.Request.Path) &&
         metricsOptions.Enabled,
         appBuilder => { appBuilder.UseMiddleware <TMiddleware>(); });
 }