From b23bffde11bf43babe7aa84bddda82414271ffaf Mon Sep 17 00:00:00 2001 From: alhardy Date: Sun, 27 Aug 2017 20:09:09 +1000 Subject: [PATCH] #186 removing dependency on Microsoft DI and configuration --- AppMetrics.ruleset | 1 + AppMetrics.sln | 2 +- ...rupted.2017-09-01T12-18-01.Description.Tmp | 13 + .../App.Metrics.Benchmarks.csproj | 2 - .../DefaultMetricContextRegistryBenchmark.cs | 7 +- .../Metrics/MeasureApdexBenchmark.cs | 1 + .../Metrics/MeasureCounterBenchmark.cs | 1 + .../MeasureCounterWithMetricItemBenchmark.cs | 1 + .../Metrics/MeasureGaugeBenchmark.cs | 1 + .../Metrics/MeasureHistogramBenchmark.cs | 1 + .../Metrics/MeasureMeterBenchmark.cs | 1 + .../Metrics/MeasureTimerBenchmark.cs | 1 + .../Fixtures/MetricContextTestFixture.cs | 9 +- .../Fixtures/MetricsCoreTestFixture.cs | 22 +- build/common.props | 1 + sandbox/MetricsSandbox/Host.cs | 91 ++---- sandbox/MetricsSandbox/MetricsSandbox.csproj | 1 - .../Abstractions/IAppMetricsEnvironment.cs | 19 -- .../App.Metrics.Abstractions.csproj | 11 +- .../Infrastructure/EnvironmentInfo.cs | 20 +- src/App.Metrics.Core/App.Metrics.Core.csproj | 25 +- .../App_Packages/LibLog.g.cs} | 14 +- .../Builder/EnvOutputFormattingBuilder.cs | 72 +++++ .../Builder/IMetricsBuilder.cs | 63 ++++ .../Builder/MetricsBuilder.cs | 136 +++++++++ .../Builder/MetricsClockBuilder.cs | 108 +++++++ .../Builder/MetricsFilterBuilder.cs | 145 +++++++++ .../Builder/MetricsOptionsBuilder.cs | 172 +++++++++++ .../Builder/MetricsOutputFormattingBuilder.cs | 72 +++++ .../MetricsReservoirSamplingBuilder.cs | 281 ++++++++++++++++++ .../DependencyInjection/IMetricsBuilder.cs | 19 -- .../IMetricsCoreBuilder.cs | 19 -- .../Internal/AppMetricsServicesHelper.cs | 44 --- .../MetricsCoreMetricsBuilderExtensions.cs | 39 --- ...MetricsCoreMetricsCoreBuilderExtensions.cs | 80 ----- .../MetricsCoreServiceCollectionExtensions.cs | 200 ------------- src/App.Metrics.Core/IMetricsRoot.cs | 49 +++ .../Infrastructure/AppMetricsEnvironment.cs | 32 -- .../Infrastructure/EnvironmentInfoProvider.cs | 2 - .../EnvironmentInfoProviderCache.cs | 9 - .../Internal/AppMetricsTaskHelper.cs | 23 ++ .../Internal/DefaultMetrics.cs | 2 - .../Internal/DefaultMetricsBuilderFactory.cs | 17 +- .../Internal/DefaultMetricsRegistry.cs | 5 +- .../ExcludeFromCodeCoverageAttribute.cs | 14 + .../AppMetricsMarkerService.cs | 2 +- .../Internal/MetricsBuilder.cs | 20 -- .../Internal/MetricsCoreBuilder.cs | 20 -- .../MetricsCoreMetricsOptionsSetup.cs | 53 ---- .../Internal/NoOp/NoOpMetrics.cs | 32 ++ .../KeyValuePairMetricsOptions.cs | 98 ++++++ src/App.Metrics.Core/MetricsOptions.cs | 40 --- src/App.Metrics.Core/MetricsRoot.cs | 75 +++++ .../DefaultSamplingReservoirProvider.cs | 3 - .../DefaultForwardDecayingReservoir.cs | 2 +- .../App.Metrics.Formatters.Ascii.csproj | 12 +- .../Builder/EnvTextOutputFormatterBuider.cs | 47 +++ .../MetricsTextOutputFormatterBuilder.cs | 47 +++ .../MetricsTextMetricsBuilderExtensions.cs | 42 --- ...MetricsTextMetricsCoreBuilderExtensions.cs | 45 --- ...atter.cs => EnvInfoTextOutputFormatter.cs} | 15 +- .../EnvInfoTextWriter.cs | 5 - .../Internal/MetricsTextOptionsSetup.cs | 31 -- .../MetricSnapshotTextWriter.cs | 1 - .../MetricsTextOutputFormatter.cs | 7 + .../App.Metrics.Formatters.Json.csproj | 12 +- .../Builder/EnvJsonOutputFormatterBuilder.cs | 47 +++ .../MetricsJsonOutputFormatterBuilder.cs | 47 +++ .../MetricsJsonMetricsBuilderExtensions.cs | 42 --- ...MetricsJsonMetricsCoreBuilderExtensions.cs | 45 --- .../EnvInfoJsonOutputFormatter.cs | 8 +- .../Internal/MetricsJsonOptionsSetup.cs | 32 -- .../MetricsJsonOutputFormatter.cs | 7 + src/App.Metrics/App.Metrics.csproj | 4 + src/App.Metrics/AppMetrics.cs | 37 +++ .../MetricsServiceCollectionExtensions.cs | 163 ---------- .../App.Metrics.Facts.csproj | 2 - .../EnvOutputFormattingBuilderTests.cs | 89 ++++++ .../Builder/MetricsClockBuilderTests.cs | 82 +++++ .../Builder/MetricsFilterBuilderTests.cs | 27 ++ .../Builder/MetricsOptionsBuilderTests.cs | 146 +++++++++ .../MetricsOutputFormattingBuilderTests.cs | 89 ++++++ .../MetricsReservoirSamplingBuilderTests.cs | 107 +++++++ .../DefaultMetricsBuilderFactoryTests.cs | 4 +- .../AppMetricsOptionExtensionsTests.cs | 2 - .../Fixtures/MetricCoreTestFixture.cs | 7 +- .../EnvironmentInfoEqualityTests.cs | 22 +- .../KeyValuePairMetricsOptionsTests.cs | 117 ++++++++ .../App.Metrics.FactsCommon.csproj | 2 - .../Fixtures/MetricsFixture.cs | 14 +- .../App.Metrics.Formatters.Ascii.Facts.csproj | 2 - ...ricsTextEnvOutputFormattingBuilderTests.cs | 28 ++ ...MetricsTextOutputFormattingBuilderTests.cs | 28 ++ .../App.Metrics.Formatters.Json.Facts.csproj | 2 - ...ricsJsonEnvOutputFormattingBuilderTests.cs | 28 ++ ...MetricsJsonOutputFormattingBuilderTests.cs | 28 ++ .../JsonFiles/env.json | 8 - .../TestFixtures/MetricProviderTestFixture.cs | 2 - 98 files changed, 2538 insertions(+), 1187 deletions(-) create mode 100644 AppMetrics.sln.DotSettings.user.Corrupted.2017-09-01T12-18-01.Description.Tmp delete mode 100644 src/App.Metrics.Abstractions/Abstractions/IAppMetricsEnvironment.cs rename src/{App.Metrics.Abstractions/App_Packages/LibLog.cs => App.Metrics.Core/App_Packages/LibLog.g.cs} (99%) create mode 100644 src/App.Metrics.Core/Builder/EnvOutputFormattingBuilder.cs create mode 100644 src/App.Metrics.Core/Builder/IMetricsBuilder.cs create mode 100644 src/App.Metrics.Core/Builder/MetricsBuilder.cs create mode 100644 src/App.Metrics.Core/Builder/MetricsClockBuilder.cs create mode 100644 src/App.Metrics.Core/Builder/MetricsFilterBuilder.cs create mode 100644 src/App.Metrics.Core/Builder/MetricsOptionsBuilder.cs create mode 100644 src/App.Metrics.Core/Builder/MetricsOutputFormattingBuilder.cs create mode 100644 src/App.Metrics.Core/Builder/MetricsReservoirSamplingBuilder.cs delete mode 100644 src/App.Metrics.Core/DependencyInjection/IMetricsBuilder.cs delete mode 100644 src/App.Metrics.Core/DependencyInjection/IMetricsCoreBuilder.cs delete mode 100644 src/App.Metrics.Core/DependencyInjection/Internal/AppMetricsServicesHelper.cs delete mode 100644 src/App.Metrics.Core/DependencyInjection/MetricsCoreMetricsBuilderExtensions.cs delete mode 100644 src/App.Metrics.Core/DependencyInjection/MetricsCoreMetricsCoreBuilderExtensions.cs delete mode 100644 src/App.Metrics.Core/DependencyInjection/MetricsCoreServiceCollectionExtensions.cs create mode 100644 src/App.Metrics.Core/IMetricsRoot.cs delete mode 100644 src/App.Metrics.Core/Infrastructure/AppMetricsEnvironment.cs create mode 100644 src/App.Metrics.Core/Internal/AppMetricsTaskHelper.cs create mode 100644 src/App.Metrics.Core/Internal/ExcludeFromCodeCoverageAttribute.cs rename src/App.Metrics.Core/{DependencyInjection/Internal => Internal/Infrastructure}/AppMetricsMarkerService.cs (87%) delete mode 100644 src/App.Metrics.Core/Internal/MetricsBuilder.cs delete mode 100644 src/App.Metrics.Core/Internal/MetricsCoreBuilder.cs delete mode 100644 src/App.Metrics.Core/Internal/MetricsCoreMetricsOptionsSetup.cs create mode 100644 src/App.Metrics.Core/Internal/NoOp/NoOpMetrics.cs create mode 100644 src/App.Metrics.Core/KeyValuePairMetricsOptions.cs create mode 100644 src/App.Metrics.Core/MetricsRoot.cs create mode 100644 src/App.Metrics.Formatters.Ascii/Builder/EnvTextOutputFormatterBuider.cs create mode 100644 src/App.Metrics.Formatters.Ascii/Builder/MetricsTextOutputFormatterBuilder.cs delete mode 100644 src/App.Metrics.Formatters.Ascii/DependencyInjection/MetricsTextMetricsBuilderExtensions.cs delete mode 100644 src/App.Metrics.Formatters.Ascii/DependencyInjection/MetricsTextMetricsCoreBuilderExtensions.cs rename src/App.Metrics.Formatters.Ascii/{EnvironmentInfoTextOutputFormatter.cs => EnvInfoTextOutputFormatter.cs} (73%) delete mode 100644 src/App.Metrics.Formatters.Ascii/Internal/MetricsTextOptionsSetup.cs create mode 100644 src/App.Metrics.Formatters.Json/Builder/EnvJsonOutputFormatterBuilder.cs create mode 100644 src/App.Metrics.Formatters.Json/Builder/MetricsJsonOutputFormatterBuilder.cs delete mode 100644 src/App.Metrics.Formatters.Json/DependencyInjection/MetricsJsonMetricsBuilderExtensions.cs delete mode 100644 src/App.Metrics.Formatters.Json/DependencyInjection/MetricsJsonMetricsCoreBuilderExtensions.cs delete mode 100644 src/App.Metrics.Formatters.Json/Internal/MetricsJsonOptionsSetup.cs create mode 100644 src/App.Metrics/AppMetrics.cs delete mode 100644 src/App.Metrics/MetricsServiceCollectionExtensions.cs create mode 100644 test/App.Metrics.Facts/Builder/EnvOutputFormattingBuilderTests.cs create mode 100644 test/App.Metrics.Facts/Builder/MetricsClockBuilderTests.cs create mode 100644 test/App.Metrics.Facts/Builder/MetricsFilterBuilderTests.cs create mode 100644 test/App.Metrics.Facts/Builder/MetricsOptionsBuilderTests.cs create mode 100644 test/App.Metrics.Facts/Builder/MetricsOutputFormattingBuilderTests.cs create mode 100644 test/App.Metrics.Facts/Builder/MetricsReservoirSamplingBuilderTests.cs create mode 100644 test/App.Metrics.Facts/Options/KeyValuePairMetricsOptionsTests.cs create mode 100644 test/App.Metrics.Formatters.Ascii.Facts/Builder/MetricsTextEnvOutputFormattingBuilderTests.cs create mode 100644 test/App.Metrics.Formatters.Ascii.Facts/Builder/MetricsTextOutputFormattingBuilderTests.cs create mode 100644 test/App.Metrics.Formatters.Json.Facts/Builder/MetricsJsonEnvOutputFormattingBuilderTests.cs create mode 100644 test/App.Metrics.Formatters.Json.Facts/Builder/MetricsJsonOutputFormattingBuilderTests.cs diff --git a/AppMetrics.ruleset b/AppMetrics.ruleset index bf53f03b..41845b22 100644 --- a/AppMetrics.ruleset +++ b/AppMetrics.ruleset @@ -121,6 +121,7 @@ + diff --git a/AppMetrics.sln b/AppMetrics.sln index 150251f8..e6929e41 100644 --- a/AppMetrics.sln +++ b/AppMetrics.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26621.2 +VisualStudioVersion = 15.0.26823.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{2D805782-756E-4C98-B22E-F502BEE95318}" EndProject diff --git a/AppMetrics.sln.DotSettings.user.Corrupted.2017-09-01T12-18-01.Description.Tmp b/AppMetrics.sln.DotSettings.user.Corrupted.2017-09-01T12-18-01.Description.Tmp new file mode 100644 index 00000000..8a4ca1bb --- /dev/null +++ b/AppMetrics.sln.DotSettings.user.Corrupted.2017-09-01T12-18-01.Description.Tmp @@ -0,0 +1,13 @@ + + + + + + VISIBLE_FILES + + + + + + + \ No newline at end of file diff --git a/benchmarks/App.Metrics.Benchmarks/App.Metrics.Benchmarks.csproj b/benchmarks/App.Metrics.Benchmarks/App.Metrics.Benchmarks.csproj index 5829c28d..debc5c7a 100644 --- a/benchmarks/App.Metrics.Benchmarks/App.Metrics.Benchmarks.csproj +++ b/benchmarks/App.Metrics.Benchmarks/App.Metrics.Benchmarks.csproj @@ -21,8 +21,6 @@ - - diff --git a/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/DefaultMetricContextRegistryBenchmark.cs b/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/DefaultMetricContextRegistryBenchmark.cs index 1a84497a..b6606319 100644 --- a/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/DefaultMetricContextRegistryBenchmark.cs +++ b/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/DefaultMetricContextRegistryBenchmark.cs @@ -10,6 +10,7 @@ using App.Metrics.Internal; using App.Metrics.Meter; using App.Metrics.ReservoirSampling; +using App.Metrics.ReservoirSampling.ExponentialDecay; using App.Metrics.Tagging; using App.Metrics.Timer; using BenchmarkDotNet.Attributes; @@ -18,7 +19,7 @@ namespace App.Metrics.Benchmarks.BenchmarkDotNetBenchmarks.Metrics { public class DefaultMetricContextRegistryBenchmark : DefaultBenchmarkBase { - private static readonly IBuildApdexMetrics ApdexBuilder = new DefaultApdexBuilder(new DefaultSamplingReservoirProvider()); + private static readonly IBuildApdexMetrics ApdexBuilder = new DefaultApdexBuilder(new DefaultSamplingReservoirProvider(() => new DefaultForwardDecayingReservoir())); private static readonly ApdexOptions ApdexOptions = new ApdexOptions { Name = "apdex" @@ -40,7 +41,7 @@ public class DefaultMetricContextRegistryBenchmark : DefaultBenchmarkBase Name = "gauge" }; - private static readonly IBuildHistogramMetrics HistogramBuilder = new DefaultHistogramBuilder(new DefaultSamplingReservoirProvider()); + private static readonly IBuildHistogramMetrics HistogramBuilder = new DefaultHistogramBuilder(new DefaultSamplingReservoirProvider(() => new DefaultForwardDecayingReservoir())); private static readonly HistogramOptions HistogramOptions = new HistogramOptions { @@ -54,7 +55,7 @@ public class DefaultMetricContextRegistryBenchmark : DefaultBenchmarkBase Name = "meter" }; - private static readonly IBuildTimerMetrics TimerBuilder = new DefaultTimerBuilder(new DefaultSamplingReservoirProvider()); + private static readonly IBuildTimerMetrics TimerBuilder = new DefaultTimerBuilder(new DefaultSamplingReservoirProvider(() => new DefaultForwardDecayingReservoir())); private static readonly TimerOptions TimerOptions = new TimerOptions { diff --git a/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureApdexBenchmark.cs b/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureApdexBenchmark.cs index ed9d69d8..ace8a8da 100644 --- a/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureApdexBenchmark.cs +++ b/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureApdexBenchmark.cs @@ -2,6 +2,7 @@ // Copyright (c) Allan Hardy. All rights reserved. // +using App.Metrics.Benchmarks.Fixtures; using App.Metrics.Benchmarks.Support; using BenchmarkDotNet.Attributes; diff --git a/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureCounterBenchmark.cs b/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureCounterBenchmark.cs index 64aabbbe..f3bb55b1 100644 --- a/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureCounterBenchmark.cs +++ b/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureCounterBenchmark.cs @@ -2,6 +2,7 @@ // Copyright (c) Allan Hardy. All rights reserved. // +using App.Metrics.Benchmarks.Fixtures; using App.Metrics.Benchmarks.Support; using BenchmarkDotNet.Attributes; diff --git a/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureCounterWithMetricItemBenchmark.cs b/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureCounterWithMetricItemBenchmark.cs index 80ce8760..c14cabc5 100644 --- a/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureCounterWithMetricItemBenchmark.cs +++ b/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureCounterWithMetricItemBenchmark.cs @@ -2,6 +2,7 @@ // Copyright (c) Allan Hardy. All rights reserved. // +using App.Metrics.Benchmarks.Fixtures; using App.Metrics.Benchmarks.Support; using BenchmarkDotNet.Attributes; diff --git a/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureGaugeBenchmark.cs b/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureGaugeBenchmark.cs index 4937845b..a4e5e204 100644 --- a/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureGaugeBenchmark.cs +++ b/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureGaugeBenchmark.cs @@ -2,6 +2,7 @@ // Copyright (c) Allan Hardy. All rights reserved. // +using App.Metrics.Benchmarks.Fixtures; using App.Metrics.Benchmarks.Support; using BenchmarkDotNet.Attributes; diff --git a/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureHistogramBenchmark.cs b/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureHistogramBenchmark.cs index 53a74b40..ec4cfe78 100644 --- a/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureHistogramBenchmark.cs +++ b/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureHistogramBenchmark.cs @@ -2,6 +2,7 @@ // Copyright (c) Allan Hardy. All rights reserved. // +using App.Metrics.Benchmarks.Fixtures; using App.Metrics.Benchmarks.Support; using BenchmarkDotNet.Attributes; diff --git a/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureMeterBenchmark.cs b/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureMeterBenchmark.cs index ce91304e..1367cdbe 100644 --- a/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureMeterBenchmark.cs +++ b/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureMeterBenchmark.cs @@ -2,6 +2,7 @@ // Copyright (c) Allan Hardy. All rights reserved. // +using App.Metrics.Benchmarks.Fixtures; using App.Metrics.Benchmarks.Support; using BenchmarkDotNet.Attributes; diff --git a/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureTimerBenchmark.cs b/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureTimerBenchmark.cs index 84da8a41..44eec99d 100644 --- a/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureTimerBenchmark.cs +++ b/benchmarks/App.Metrics.Benchmarks/BenchmarkDotNetBenchmarks/Metrics/MeasureTimerBenchmark.cs @@ -2,6 +2,7 @@ // Copyright (c) Allan Hardy. All rights reserved. // +using App.Metrics.Benchmarks.Fixtures; using App.Metrics.Benchmarks.Support; using BenchmarkDotNet.Attributes; diff --git a/benchmarks/App.Metrics.Benchmarks/Fixtures/MetricContextTestFixture.cs b/benchmarks/App.Metrics.Benchmarks/Fixtures/MetricContextTestFixture.cs index 2afdd3a2..dba5f763 100644 --- a/benchmarks/App.Metrics.Benchmarks/Fixtures/MetricContextTestFixture.cs +++ b/benchmarks/App.Metrics.Benchmarks/Fixtures/MetricContextTestFixture.cs @@ -12,6 +12,7 @@ using App.Metrics.Meter; using App.Metrics.Registry; using App.Metrics.ReservoirSampling; +using App.Metrics.ReservoirSampling.ExponentialDecay; using App.Metrics.Tagging; using App.Metrics.Timer; @@ -57,13 +58,15 @@ public MetricContextTestFixture() { "key2", "value2" } }; + var samplingProvider = new DefaultSamplingReservoirProvider(() => new DefaultForwardDecayingReservoir()); + Registry = new DefaultMetricContextRegistry("context_label", tags); - ApdexBuilder = new DefaultApdexBuilder(new DefaultSamplingReservoirProvider()); - HistogramBuilder = new DefaultHistogramBuilder(new DefaultSamplingReservoirProvider()); + ApdexBuilder = new DefaultApdexBuilder(samplingProvider); + HistogramBuilder = new DefaultHistogramBuilder(samplingProvider); CounterBuilder = new DefaultCounterBuilder(); GaugeBuilder = new DefaultGaugeBuilder(); MeterBuilder = new DefaultMeterBuilder(); - TimerBuilder = new DefaultTimerBuilder(new DefaultSamplingReservoirProvider()); + TimerBuilder = new DefaultTimerBuilder(samplingProvider); Clock = new StopwatchClock(); } diff --git a/benchmarks/App.Metrics.Benchmarks/Fixtures/MetricsCoreTestFixture.cs b/benchmarks/App.Metrics.Benchmarks/Fixtures/MetricsCoreTestFixture.cs index a8815f24..ffa6357b 100644 --- a/benchmarks/App.Metrics.Benchmarks/Fixtures/MetricsCoreTestFixture.cs +++ b/benchmarks/App.Metrics.Benchmarks/Fixtures/MetricsCoreTestFixture.cs @@ -4,7 +4,6 @@ using System; using System.Linq; -using Microsoft.Extensions.DependencyInjection; namespace App.Metrics.Benchmarks.Fixtures { @@ -24,13 +23,20 @@ public class MetricsCoreTestFixture : IDisposable public MetricsCoreTestFixture() { - var services = new ServiceCollection(); - services.AddLogging(); - services.AddMetrics(); - - var provider = services.BuildServiceProvider(); - - Metrics = provider.GetRequiredService(); + Metrics = new MetricsBuilder() + .Options.Configure(options => + { + options.DefaultContextLabel = "Testing"; + options.MetricsEnabled = true; + }) + .OutputEnvInfo.AsJson() + .OutputEnvInfo.AsPlainText() + .OutputMetrics.AsPlainText() + .OutputMetrics.AsJson() + .SampleWith.AlgorithmR() + .Filter.ByIncludingOnlyTypes(MetricType.Counter) + .TimeWith.StopwatchClock() + .Build(); } public IMetrics Metrics { get; } diff --git a/build/common.props b/build/common.props index c377a117..0a38fe95 100644 --- a/build/common.props +++ b/build/common.props @@ -18,6 +18,7 @@ false false false + latest ..\..\AppMetrics.ruleset $(MSBuildThisFileDirectory)Key.snk true diff --git a/sandbox/MetricsSandbox/Host.cs b/sandbox/MetricsSandbox/Host.cs index bb0d248c..891e66f8 100644 --- a/sandbox/MetricsSandbox/Host.cs +++ b/sandbox/MetricsSandbox/Host.cs @@ -6,13 +6,9 @@ using System.IO; using System.Text; using System.Threading; +using System.Threading.Tasks; using App.Metrics; -using App.Metrics.Filtering; -using App.Metrics.Filters; -using App.Metrics.Infrastructure; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using Serilog; namespace MetricsSandbox @@ -21,59 +17,46 @@ public static class Host { private static readonly Random Rnd = new Random(); - public static IConfigurationRoot Configuration { get; set; } + private static IConfigurationRoot Configuration { get; set; } - // public static async Task Main(string[] args) - public static void Main(string[] args) + private static IMetricsRoot Metrics { get; set; } + + public static async Task Main() { Init(); - IServiceCollection serviceCollection = new ServiceCollection(); - var metricsFilter = new DefaultMetricsFilter(); - - ConfigureServices(serviceCollection, metricsFilter); - - var provider = serviceCollection.BuildServiceProvider(); - var metrics = provider.GetRequiredService(); - var metricsProvider = provider.GetRequiredService(); - var envInfoProvider = provider.GetRequiredService(); - var metricsOptionsAccessor = provider.GetRequiredService>(); - var cancellationTokenSource = new CancellationTokenSource(); - WriteEnv(envInfoProvider, metricsOptionsAccessor, cancellationTokenSource); + await WriteEnvAsync(cancellationTokenSource); Console.ReadKey(); RunUntilEsc( TimeSpan.FromSeconds(5), cancellationTokenSource, - () => + async () => { Console.Clear(); - RecordMetrics(metrics); + RecordMetrics(); - WriteMetrics(metricsProvider, metricsFilter, metricsOptionsAccessor, cancellationTokenSource); + await WriteMetricsAsync(cancellationTokenSource); }); } - private static void WriteEnv( - EnvironmentInfoProvider envInfoProvider, - IOptions metricsOptionsAccessor, - CancellationTokenSource cancellationTokenSource) + private static async Task WriteEnvAsync(CancellationTokenSource cancellationTokenSource) { Console.WriteLine("Environment Information"); Console.WriteLine("-------------------------------------------"); - foreach (var formatter in metricsOptionsAccessor.Value.OutputEnvFormatters) + foreach (var formatter in Metrics.OutputEnvFormatters) { Console.WriteLine($"Formatter: {formatter.GetType().FullName}"); Console.WriteLine("-------------------------------------------"); using (var stream = new MemoryStream()) { - formatter.WriteAsync(stream, envInfoProvider.Build(), cancellationTokenSource.Token).GetAwaiter().GetResult(); + await formatter.WriteAsync(stream, Metrics.EnvironmentInfo, cancellationTokenSource.Token); var result = Encoding.UTF8.GetString(stream.ToArray()); @@ -82,25 +65,21 @@ public static void Main(string[] args) } } - private static void WriteMetrics( - IProvideMetricValues metricsProvider, - IFilterMetrics metricsFilter, - IOptions metricsOptionsAccessor, - CancellationTokenSource cancellationTokenSource) + private static async Task WriteMetricsAsync(CancellationTokenSource cancellationTokenSource) { - var metricsData = metricsProvider.Get(metricsFilter); + var metricsData = Metrics.Snapshot.Get(); Console.WriteLine("Metrics Formatters"); Console.WriteLine("-------------------------------------------"); - foreach (var formatter in metricsOptionsAccessor.Value.OutputMetricsFormatters) + foreach (var formatter in Metrics.OutputMetricsFormatters) { Console.WriteLine($"Formatter: {formatter.GetType().FullName}"); Console.WriteLine("-------------------------------------------"); using (var stream = new MemoryStream()) { - formatter.WriteAsync(stream, metricsData, cancellationTokenSource.Token).GetAwaiter().GetResult(); + await formatter.WriteAsync(stream, metricsData, cancellationTokenSource.Token); var result = Encoding.UTF8.GetString(stream.ToArray()); @@ -109,46 +88,39 @@ public static void Main(string[] args) } } - private static void RecordMetrics(IMetrics metrics) + private static void RecordMetrics() { - metrics.Measure.Counter.Increment(ApplicationsMetricsRegistry.CounterOne); - metrics.Measure.Gauge.SetValue(ApplicationsMetricsRegistry.GaugeOne, Rnd.Next(0, 100)); - metrics.Measure.Histogram.Update(ApplicationsMetricsRegistry.HistogramOne, Rnd.Next(0, 100)); - metrics.Measure.Meter.Mark(ApplicationsMetricsRegistry.MeterOne, Rnd.Next(0, 100)); + Metrics.Measure.Counter.Increment(ApplicationsMetricsRegistry.CounterOne); + Metrics.Measure.Gauge.SetValue(ApplicationsMetricsRegistry.GaugeOne, Rnd.Next(0, 100)); + Metrics.Measure.Histogram.Update(ApplicationsMetricsRegistry.HistogramOne, Rnd.Next(0, 100)); + Metrics.Measure.Meter.Mark(ApplicationsMetricsRegistry.MeterOne, Rnd.Next(0, 100)); - using (metrics.Measure.Timer.Time(ApplicationsMetricsRegistry.TimerOne)) + using (Metrics.Measure.Timer.Time(ApplicationsMetricsRegistry.TimerOne)) { Thread.Sleep(Rnd.Next(0, 100)); } - using (metrics.Measure.Apdex.Track(ApplicationsMetricsRegistry.ApdexOne)) + using (Metrics.Measure.Apdex.Track(ApplicationsMetricsRegistry.ApdexOne)) { Thread.Sleep(Rnd.Next(0, 100)); } } - private static void ConfigureServices(IServiceCollection services, IFilterMetrics metricsFilter) + private static void Init() { + var configurationBuilder = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json"); + + Configuration = configurationBuilder.Build(); + Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() .WriteTo.LiterateConsole() .WriteTo.Seq("http://localhost:5341") .CreateLogger(); - services.AddMetrics(); - - // services. - // AddMetricsCore(). - // AddClockType(). - // AddGlobalFilter(metricsFilter). - // AddDefaultReservoir(() => new DefaultAlgorithmRReservoir()); - } - - private static void Init() - { - var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json"); - - Configuration = builder.Build(); + Metrics = AppMetrics.CreateDefaultBuilder().Build(); } private static void RunUntilEsc(TimeSpan delayBetweenRun, CancellationTokenSource cancellationTokenSource, Action action) @@ -160,6 +132,7 @@ private static void RunUntilEsc(TimeSpan delayBetweenRun, CancellationTokenSourc while (!Console.KeyAvailable) { action(); + Thread.Sleep(delayBetweenRun); } diff --git a/sandbox/MetricsSandbox/MetricsSandbox.csproj b/sandbox/MetricsSandbox/MetricsSandbox.csproj index 3358e524..7e81b8a1 100644 --- a/sandbox/MetricsSandbox/MetricsSandbox.csproj +++ b/sandbox/MetricsSandbox/MetricsSandbox.csproj @@ -14,7 +14,6 @@ - diff --git a/src/App.Metrics.Abstractions/Abstractions/IAppMetricsEnvironment.cs b/src/App.Metrics.Abstractions/Abstractions/IAppMetricsEnvironment.cs deleted file mode 100644 index c425b33e..00000000 --- a/src/App.Metrics.Abstractions/Abstractions/IAppMetricsEnvironment.cs +++ /dev/null @@ -1,19 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -// ReSharper disable CheckNamespace -namespace App.Metrics - // ReSharper restore CheckNamespace -{ - public interface IAppMetricsEnvironment - { - string ApplicationName { get; } - - string ApplicationVersion { get; } - - string RuntimeFramework { get; } - - string RuntimeFrameworkVersion { get; } - } -} \ No newline at end of file diff --git a/src/App.Metrics.Abstractions/App.Metrics.Abstractions.csproj b/src/App.Metrics.Abstractions/App.Metrics.Abstractions.csproj index 15b4fb8e..fdab2430 100644 --- a/src/App.Metrics.Abstractions/App.Metrics.Abstractions.csproj +++ b/src/App.Metrics.Abstractions/App.Metrics.Abstractions.csproj @@ -4,22 +4,13 @@ App Metrics Core abstractions and interfaces for metric types, reporting, filtering and more. - netstandard1.6 + netstandard1.1 App.Metrics true appmetrics;metrics - - TRACE;DEBUG;NETSTANDARD1_6;LIBLOG_PORTABLE;LIBLOG_PUBLIC - - - - TRACE;RELEASE;NETSTANDARD1_6;LIBLOG_PORTABLE;LIBLOG_PUBLIC - - - diff --git a/src/App.Metrics.Abstractions/Infrastructure/EnvironmentInfo.cs b/src/App.Metrics.Abstractions/Infrastructure/EnvironmentInfo.cs index a6b7f477..259fd23d 100644 --- a/src/App.Metrics.Abstractions/Infrastructure/EnvironmentInfo.cs +++ b/src/App.Metrics.Abstractions/Infrastructure/EnvironmentInfo.cs @@ -19,7 +19,6 @@ public EnvironmentInfo(IDictionary entries) Value; MachineName = entries.FirstOrDefault(e => string.Equals(e.Key, "MachineName", StringComparison.OrdinalIgnoreCase)).Value; ProcessArchitecture = entries.FirstOrDefault(e => string.Equals(e.Key, "ProcessArchitecture", StringComparison.OrdinalIgnoreCase)).Value; - ProcessName = entries.FirstOrDefault(e => string.Equals(e.Key, "ProcessName", StringComparison.OrdinalIgnoreCase)).Value; OperatingSystemPlatform = entries.FirstOrDefault(e => string.Equals(e.Key, "OperatingSystemPlatform", StringComparison.OrdinalIgnoreCase)).Value; OperatingSystemVersion = entries.FirstOrDefault(e => string.Equals(e.Key, "OperatingSystemVersion", StringComparison.OrdinalIgnoreCase)). @@ -27,7 +26,6 @@ public EnvironmentInfo(IDictionary entries) OperatingSystemArchitecture = entries.FirstOrDefault(e => string.Equals(e.Key, "OperatingSystemArchitecture", StringComparison.OrdinalIgnoreCase)).Value; ProcessorCount = entries.FirstOrDefault(e => string.Equals(e.Key, "CPUCount", StringComparison.OrdinalIgnoreCase)).Value; - HostName = entries.FirstOrDefault(e => string.Equals(e.Key, "HostName", StringComparison.OrdinalIgnoreCase)).Value; LocalTimeString = entries.FirstOrDefault(e => string.Equals(e.Key, "LocalTime", StringComparison.OrdinalIgnoreCase)).Value; EntryAssemblyName = entries.FirstOrDefault(e => string.Equals(e.Key, "EntryAssemblyName", StringComparison.OrdinalIgnoreCase)).Value; EntryAssemblyVersion = entries.FirstOrDefault(e => string.Equals(e.Key, "EntryAssemblyVersion", StringComparison.OrdinalIgnoreCase)). @@ -37,12 +35,10 @@ public EnvironmentInfo(IDictionary entries) { new EnvironmentInfoEntry("FrameworkDescription", FrameworkDescription), new EnvironmentInfoEntry("MachineName", MachineName), - new EnvironmentInfoEntry("ProcessName", ProcessName), new EnvironmentInfoEntry("OperatingSystemPlatform", OperatingSystemPlatform), new EnvironmentInfoEntry("OperatingSystemVersion", OperatingSystemVersion), new EnvironmentInfoEntry("OperatingSystemArchitecture", OperatingSystemArchitecture), new EnvironmentInfoEntry("CPUCount", ProcessorCount), - new EnvironmentInfoEntry("HostName", HostName), new EnvironmentInfoEntry("LocalTime", LocalTimeString), new EnvironmentInfoEntry("EntryAssemblyName", EntryAssemblyName), new EnvironmentInfoEntry("EntryAssemblyVersion", EntryAssemblyVersion) @@ -53,27 +49,23 @@ public EnvironmentInfo(IDictionary entries) string frameworkDescription, string entryAssemblyName, string entryAssemblyVersion, - string hostName, string localTimeString, string machineName, string operatingSystemPlatform, string operatingSystemVersion, string operatingSystemArchitecture, string processArchitecture, - string processName, string processorCount) { FrameworkDescription = frameworkDescription; EntryAssemblyName = entryAssemblyName; EntryAssemblyVersion = entryAssemblyVersion; - HostName = hostName; LocalTimeString = localTimeString; MachineName = machineName; OperatingSystemArchitecture = operatingSystemArchitecture; OperatingSystemPlatform = operatingSystemPlatform; OperatingSystemVersion = operatingSystemVersion; ProcessArchitecture = processArchitecture; - ProcessName = processName; ProcessorCount = processorCount; _entries = new[] @@ -81,12 +73,10 @@ public EnvironmentInfo(IDictionary entries) new EnvironmentInfoEntry("FrameworkDescription", FrameworkDescription), new EnvironmentInfoEntry("MachineName", MachineName), new EnvironmentInfoEntry("ProcessArchitecture", ProcessArchitecture), - new EnvironmentInfoEntry("ProcessName", ProcessName), new EnvironmentInfoEntry("OperatingSystemArchitecture", OperatingSystemArchitecture), new EnvironmentInfoEntry("OperatingSystemPlatform", OperatingSystemPlatform), new EnvironmentInfoEntry("OperatingSystemVersion", OperatingSystemVersion), new EnvironmentInfoEntry("CPUCount", ProcessorCount), - new EnvironmentInfoEntry("HostName", HostName), new EnvironmentInfoEntry("LocalTime", LocalTimeString), new EnvironmentInfoEntry("EntryAssemblyName", EntryAssemblyName), new EnvironmentInfoEntry("EntryAssemblyVersion", EntryAssemblyVersion) @@ -101,8 +91,6 @@ public EnvironmentInfo(IDictionary entries) public string FrameworkDescription { get; } - public string HostName { get; } - public string LocalTimeString { get; } public string MachineName { get; } @@ -115,8 +103,6 @@ public EnvironmentInfo(IDictionary entries) public string ProcessArchitecture { get; } - public string ProcessName { get; } - public string ProcessorCount { get; } public static bool operator ==(EnvironmentInfo left, EnvironmentInfo right) { return left.Equals(right); } @@ -140,14 +126,12 @@ public override int GetHashCode() var hashCode = FrameworkDescription != null ? FrameworkDescription.GetHashCode() : 0; hashCode = (hashCode * 397) ^ (EntryAssemblyName != null ? EntryAssemblyName.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (EntryAssemblyVersion != null ? EntryAssemblyVersion.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (HostName != null ? HostName.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (LocalTimeString != null ? LocalTimeString.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (MachineName != null ? MachineName.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (OperatingSystemPlatform != null ? OperatingSystemPlatform.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (OperatingSystemArchitecture != null ? OperatingSystemArchitecture.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (OperatingSystemVersion != null ? OperatingSystemVersion.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (ProcessArchitecture != null ? ProcessArchitecture.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (ProcessName != null ? ProcessName.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (ProcessorCount != null ? ProcessorCount.GetHashCode() : 0); return hashCode; } @@ -156,12 +140,12 @@ public override int GetHashCode() public bool Equals(EnvironmentInfo other) { return string.Equals(FrameworkDescription, other.FrameworkDescription) && string.Equals(EntryAssemblyName, other.EntryAssemblyName) && - string.Equals(EntryAssemblyVersion, other.EntryAssemblyVersion) && string.Equals(HostName, other.HostName) && + string.Equals(EntryAssemblyVersion, other.EntryAssemblyVersion) && string.Equals(LocalTimeString, other.LocalTimeString) && string.Equals(MachineName, other.MachineName) && string.Equals(OperatingSystemPlatform, other.OperatingSystemPlatform) && string.Equals(OperatingSystemArchitecture, other.OperatingSystemArchitecture) && string.Equals(OperatingSystemVersion, other.OperatingSystemVersion) && - string.Equals(ProcessArchitecture, other.ProcessArchitecture) && string.Equals(ProcessName, other.ProcessName) && + string.Equals(ProcessArchitecture, other.ProcessArchitecture) && string.Equals(ProcessorCount, other.ProcessorCount); } } diff --git a/src/App.Metrics.Core/App.Metrics.Core.csproj b/src/App.Metrics.Core/App.Metrics.Core.csproj index bf57b3b9..a0d15e0c 100644 --- a/src/App.Metrics.Core/App.Metrics.Core.csproj +++ b/src/App.Metrics.Core/App.Metrics.Core.csproj @@ -3,8 +3,8 @@ - App Metrics core components. Contains metric types and default implementations for metric reporting, filtering and more. - netstandard2.0 + App Metrics core components. Contains metric types and default implementations for metric reporting, filtering and more. + netstandard1.6;net452 App.Metrics true appmetrics;metrics @@ -12,12 +12,29 @@ - - + + + $(DefineConstants);LIBLOG_PORTABLE;LIBLOG_PUBLIC + + + + $(DefineConstants);LIBLOG_PORTABLE;LIBLOG_PUBLIC + + + + $(DefineConstants);CLASSIC;LIBLOG_PORTABLE;LIBLOG_PUBLIC + + + + + + + + diff --git a/src/App.Metrics.Abstractions/App_Packages/LibLog.cs b/src/App.Metrics.Core/App_Packages/LibLog.g.cs similarity index 99% rename from src/App.Metrics.Abstractions/App_Packages/LibLog.cs rename to src/App.Metrics.Core/App_Packages/LibLog.g.cs index 2bf565c4..9b7e64a9 100644 --- a/src/App.Metrics.Abstractions/App_Packages/LibLog.cs +++ b/src/App.Metrics.Core/App_Packages/LibLog.g.cs @@ -1,8 +1,8 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -#pragma warning disable SA1000, SA1633, SA1005, SA1513, SA1404, SA1313, SA1402, SA1501, SA1214, SA1313, SA1204, SA1308, SA1403, SA1110, SA1611, SA1028, SA1649, SA1507, SA1118, SA1009, SA1111, SA1616, SA1649, SA1028, SA1516, SA1127, SA1204, SA1601, SA1308, SA1402, SA1114, SA1116, SA1202, SA1403, SA1117, SA1503 +//------------------------------------------------------------------------------ +// +// StyleCop Ignore +// +//------------------------------------------------------------------------------ //=============================================================================== // LibLog // @@ -2387,6 +2387,4 @@ public void Dispose() } } } -} - -#pragma warning restore SA1000, SA1633, SA1005, SA1513, SA1404, SA1313, SA1402, SA1501, SA1214, SA1313, SA1204, SA1308, SA1403, SA1110, SA1611, SA1028, SA1649, SA1507, SA1118, SA1009, SA1111, SA1616, SA1649, SA1028, SA1516, SA1127, SA1204, SA1601, SA1308, SA1402, SA1114, SA1116, SA1202, SA1403, SA1117, SA1503 \ No newline at end of file +} \ No newline at end of file diff --git a/src/App.Metrics.Core/Builder/EnvOutputFormattingBuilder.cs b/src/App.Metrics.Core/Builder/EnvOutputFormattingBuilder.cs new file mode 100644 index 00000000..ad958455 --- /dev/null +++ b/src/App.Metrics.Core/Builder/EnvOutputFormattingBuilder.cs @@ -0,0 +1,72 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System; +using App.Metrics.Formatters; + +// ReSharper disable CheckNamespace +namespace App.Metrics + // ReSharper restore CheckNamespace +{ + /// + /// Builder for configuring environment information output formatting using an . + /// + public class EnvOutputFormattingBuilder + { + private readonly IMetricsBuilder _metricsBuilder; + private readonly Action _formatter; + + internal EnvOutputFormattingBuilder( + IMetricsBuilder metricsBuilder, + Action formatter) + { + _metricsBuilder = metricsBuilder ?? throw new ArgumentNullException(nameof(metricsBuilder)); + _formatter = formatter ?? throw new ArgumentNullException(nameof(formatter)); + } + + /// + /// + /// Uses the specifed as one of the available formatters when reporting environment information. + /// + /// + /// Mulitple formatters can be used, in which case the will be set to the first configured formatter. + /// + /// + /// An instance used to format environment information when reporting. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder Using(IEnvOutputFormatter formatter) + { + if (formatter == null) + { + throw new ArgumentNullException(nameof(formatter)); + } + + _formatter(formatter); + + return _metricsBuilder; + } + + /// + /// + /// Uses the specifed as one of the available formatters when reporting environment information. + /// + /// + /// Mulitple formatters can be used, in which case the will be set to the first configured formatter. + /// + /// + /// An type used to format environment information when reporting. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder Using() + where TEvnOutputFormatter : IEnvOutputFormatter, new() + { + _formatter(new TEvnOutputFormatter()); + + return _metricsBuilder; + } + } +} diff --git a/src/App.Metrics.Core/Builder/IMetricsBuilder.cs b/src/App.Metrics.Core/Builder/IMetricsBuilder.cs new file mode 100644 index 00000000..daee4639 --- /dev/null +++ b/src/App.Metrics.Core/Builder/IMetricsBuilder.cs @@ -0,0 +1,63 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using App.Metrics.Filters; +using App.Metrics.ReservoirSampling.ExponentialDecay; + +// ReSharper disable CheckNamespace +namespace App.Metrics + // ReSharper restore CheckNamespace +{ + /// + /// An interface for configuring App Metrics services and options. + /// + public interface IMetricsBuilder + { + /// + /// Builder for configuring the default reservoir sampling using an . Reservoir sampling is used on specific metrics types. By default is set to . + /// + MetricsReservoirSamplingBuilder SampleWith { get; } + + /// + /// Builder for configuring core App Metrics options. + /// + MetricsOptionsBuilder Options { get; } + + /// + /// + /// Builder for configuring environment information output formatting for reporting. + /// + /// + /// Mulitple formatters can be used, in which case the will be set to the first configured formatter. + /// + /// + EnvOutputFormattingBuilder OutputEnvInfo { get; } + + /// + /// + /// Builder for configuring metrics output formatting for reporting. + /// + /// + /// Mulitple formatters can be used, in which case the will be set to the first configured formatter. + /// + /// + MetricsOutputFormattingBuilder OutputMetrics { get; } + + /// + /// Builder for configuring the used for specific metrics types which requiring timing. + /// + MetricsClockBuilder TimeWith { get; } + + /// + /// Builder for configuring the used to globally filter specific metrics when reporting. + /// + MetricsFilterBuilder Filter { get; } + + /// + /// Builds an with the services configured via an . + /// + /// An with services configured via an . + IMetricsRoot Build(); + } +} \ No newline at end of file diff --git a/src/App.Metrics.Core/Builder/MetricsBuilder.cs b/src/App.Metrics.Core/Builder/MetricsBuilder.cs new file mode 100644 index 00000000..1818ed8c --- /dev/null +++ b/src/App.Metrics.Core/Builder/MetricsBuilder.cs @@ -0,0 +1,136 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System.Linq; +using App.Metrics.Filtering; +using App.Metrics.Filters; +using App.Metrics.Formatters; +using App.Metrics.Infrastructure; +using App.Metrics.Internal; +using App.Metrics.Internal.NoOp; +using App.Metrics.Registry; +using App.Metrics.ReservoirSampling; +using App.Metrics.ReservoirSampling.ExponentialDecay; +using App.Metrics.Tagging; + +// ReSharper disable CheckNamespace +namespace App.Metrics + // ReSharper restore CheckNamespace +{ + public class MetricsBuilder : IMetricsBuilder + { + private readonly MetricsFormatterCollection _metricsOutputFormatters = new MetricsFormatterCollection(); + private readonly EnvFormatterCollection _envFormatters = new EnvFormatterCollection(); + private readonly EnvironmentInfoProvider _environmentInfoProvider = new EnvironmentInfoProvider(); + private IMetricsOutputFormatter _defaultMetricsOutputFormatter; + private IEnvOutputFormatter _defauEnvOutputFormatter; + private DefaultSamplingReservoirProvider _defaultSamplingReservoir = new DefaultSamplingReservoirProvider(() => new DefaultForwardDecayingReservoir()); + private IFilterMetrics _metricsFilter = new NoOpMetricsFilter(); + private IClock _clock = new StopwatchClock(); + private MetricsOptions _options = new MetricsOptions(); + + /// + public MetricsFilterBuilder Filter + { + get + { + return new MetricsFilterBuilder( + this, + metricsFilter => + { + _metricsFilter = metricsFilter; + }); + } + } + + /// + public MetricsClockBuilder TimeWith + { + get + { + return new MetricsClockBuilder( + this, + clock => + { + _clock = clock; + }); + } + } + + /// + public MetricsOutputFormattingBuilder OutputMetrics => new MetricsOutputFormattingBuilder(this, formatter => + { + if (_defaultMetricsOutputFormatter == null) + { + _defaultMetricsOutputFormatter = formatter; + } + + _metricsOutputFormatters.Add(formatter); + }); + + /// + public EnvOutputFormattingBuilder OutputEnvInfo => new EnvOutputFormattingBuilder(this, formatter => + { + if (_defauEnvOutputFormatter == null) + { + _defauEnvOutputFormatter = formatter; + } + + _envFormatters.Add(formatter); + }); + + /// + public MetricsOptionsBuilder Options + { + get + { + return new MetricsOptionsBuilder( + this, + options => + { + _options = options; + }, + _environmentInfoProvider); + } + } + + /// + public MetricsReservoirSamplingBuilder SampleWith + { + get + { + return new MetricsReservoirSamplingBuilder( + this, + reservoir => + { + _defaultSamplingReservoir = reservoir; + }); + } + } + + /// + public IMetricsRoot Build() + { + IMetricsRegistry registry = new NullMetricsRegistry(); + + if (_options.MetricsEnabled) + { + registry = new DefaultMetricsRegistry(_options.DefaultContextLabel, _clock, ContextRegistry); + } + + var builderFactory = new DefaultMetricsBuilderFactory(_defaultSamplingReservoir); + var measure = new DefaultMeasureMetricsProvider(registry, builderFactory, _clock); + var provider = new DefaultMetricsProvider(registry, builderFactory, _clock); + var snapshot = new DefaultMetricValuesProvider(_metricsFilter, registry); + var manage = new DefaultMetricsManager(registry); + var metrics = new DefaultMetrics(_clock, _metricsFilter, measure, builderFactory, provider, snapshot, manage); + var defaultMetricsOutputFormatter = _defaultMetricsOutputFormatter ?? _metricsOutputFormatters.FirstOrDefault(); + var defaultEnvOutputFormatter = _defauEnvOutputFormatter ?? _envFormatters.FirstOrDefault(); + + return new MetricsRoot(metrics, _options, _metricsOutputFormatters, _envFormatters, defaultMetricsOutputFormatter, defaultEnvOutputFormatter, _environmentInfoProvider); + + IMetricContextRegistry ContextRegistry(string context) => new DefaultMetricContextRegistry(context, new GlobalMetricTags(_options.GlobalTags)); + } + } +} diff --git a/src/App.Metrics.Core/Builder/MetricsClockBuilder.cs b/src/App.Metrics.Core/Builder/MetricsClockBuilder.cs new file mode 100644 index 00000000..3eed8854 --- /dev/null +++ b/src/App.Metrics.Core/Builder/MetricsClockBuilder.cs @@ -0,0 +1,108 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System; +using App.Metrics.Infrastructure; + +// ReSharper disable CheckNamespace +namespace App.Metrics + // ReSharper restore CheckNamespace +{ + /// + /// Builder for configuring the used for timing when recording specific metrics types e.g. . + /// + public class MetricsClockBuilder + { + private readonly Action _clock; + private readonly IMetricsBuilder _metricsBuilder; + + internal MetricsClockBuilder( + IMetricsBuilder metricsBuilder, + Action clock) + { + _metricsBuilder = metricsBuilder ?? throw new ArgumentNullException(nameof(metricsBuilder)); + _clock = clock ?? throw new ArgumentNullException(nameof(clock)); + } + + /// + /// + /// Uses the specifed to time specific s. e.g. . + /// + /// + /// A single should be configured. The last configured will be used. + /// + /// + /// An instance used for timing. e.g. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder Clock(IClock clock) + { + if (clock == null) + { + throw new ArgumentNullException(nameof(clock)); + } + + _clock(clock); + + return _metricsBuilder; + } + + /// + /// + /// Uses the specifed to time specific s. e.g. . + /// + /// + /// A single should be configured. The last configured will be used. + /// + /// + /// An type used for timing. e.g. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder Clock() + where TClock : class, IClock, new() + { + _clock(new TClock()); + + return _metricsBuilder; + } + + /// + /// + /// Uses the to time specific s. e.g. . + /// + /// + /// A single should be configured. The last configured will be used. + /// + /// + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder StopwatchClock() + { + Clock(); + + return _metricsBuilder; + } + + /// + /// + /// Uses the to time specific s. e.g. . + /// + /// + /// A single should be configured. The last configured will be used. + /// + /// + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder SystemClock() + { + Clock(); + + return _metricsBuilder; + } + } +} \ No newline at end of file diff --git a/src/App.Metrics.Core/Builder/MetricsFilterBuilder.cs b/src/App.Metrics.Core/Builder/MetricsFilterBuilder.cs new file mode 100644 index 00000000..e9f97397 --- /dev/null +++ b/src/App.Metrics.Core/Builder/MetricsFilterBuilder.cs @@ -0,0 +1,145 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System; +using App.Metrics.Filtering; +using App.Metrics.Filters; + +// ReSharper disable CheckNamespace +namespace App.Metrics + // ReSharper restore CheckNamespace +{ + /// + /// Builder for configuring the used for filtering metrics when their values are fetched. + /// + public class MetricsFilterBuilder + { + private readonly IFilterMetrics _filter; + private readonly IMetricsBuilder _metricsBuilder; + private readonly Action _metricsFilter; + + internal MetricsFilterBuilder( + IMetricsBuilder metricsBuilder, + Action metricsFilter) + { + _metricsBuilder = metricsBuilder ?? throw new ArgumentNullException(nameof(metricsBuilder)); + _metricsFilter = metricsFilter ?? throw new ArgumentNullException(nameof(metricsFilter)); + _filter = new DefaultMetricsFilter(); + } + + /// + /// Filters metrics the specified context. Metrics can be grouped using a context label. The default context label used + /// can be configured on . + /// + /// The context label to filter by. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder ByIncludingOnlyContext(string context) + { + _filter.WhereContext(context); + + _metricsFilter(_filter); + + return _metricsBuilder; + } + + /// + /// Filters metrics the specified tag key value pair. When fetched only metrics with a matching key and value will be returned. + /// + /// The tag key value pair to filter by. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder ByIncludingOnlyTagKeyValues(TagKeyValueFilter tagKeyValues) + { + _filter.WhereMetricTaggedWithKeyValue(tagKeyValues); + + _metricsFilter(_filter); + + return _metricsBuilder; + } + + /// + /// Filters metrics the specified tag key. When fetched only metrics with a matching tag key. + /// + /// The tag to filter by. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder ByIncludingOnlyTags(params string[] tagKeys) + { + _filter.WhereMetricTaggedWithKey(tagKeys); + + _metricsFilter(_filter); + + return _metricsBuilder; + } + + /// + /// Filters metrisc the specified s. + /// + /// The s to include when fetching metrics. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder ByIncludingOnlyTypes(params MetricType[] types) + { + _filter.WhereType(types); + + _metricsFilter(_filter); + + return _metricsBuilder; + } + + /// + /// + /// Uses the specifed to ftiler metrics when their values are fetched. + /// + /// + /// A single should be configured. The last configured + /// will be used. + /// + /// + /// An instance used for filtering metrics. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder With(IFilterMetrics filter) + { + if (filter == null) + { + throw new ArgumentNullException(nameof(filter)); + } + + _metricsFilter(filter); + + return _metricsBuilder; + } + + /// + /// + /// Uses the specifed setup to ftiler metrics when their values + /// are fetched. + /// + /// + /// An instance used for filtering metrics. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder With(Action setupAction) + { + if (setupAction == null) + { + throw new ArgumentNullException(nameof(setupAction)); + } + + setupAction(_filter); + + _metricsFilter(_filter); + + return _metricsBuilder; + } + } +} \ No newline at end of file diff --git a/src/App.Metrics.Core/Builder/MetricsOptionsBuilder.cs b/src/App.Metrics.Core/Builder/MetricsOptionsBuilder.cs new file mode 100644 index 00000000..ee60baa9 --- /dev/null +++ b/src/App.Metrics.Core/Builder/MetricsOptionsBuilder.cs @@ -0,0 +1,172 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System; +using System.Collections.Generic; +using App.Metrics.Infrastructure; + +// ReSharper disable CheckNamespace +namespace App.Metrics + // ReSharper restore CheckNamespace +{ + /// + /// Builder for configuring the . + /// + public class MetricsOptionsBuilder + { + private readonly EnvironmentInfoProvider _environmentInfoProvider; + private readonly IMetricsBuilder _metricsBuilder; + private readonly Action _setupAction; + + internal MetricsOptionsBuilder( + IMetricsBuilder metricsBuilder, + Action options, + EnvironmentInfoProvider environmentInfoProvider) + { + _environmentInfoProvider = environmentInfoProvider ?? throw new ArgumentNullException(nameof(environmentInfoProvider)); + _metricsBuilder = metricsBuilder ?? throw new ArgumentNullException(nameof(metricsBuilder)); + _setupAction = options ?? throw new ArgumentNullException(nameof(options)); + } + + /// + /// + /// Uses the specifed instance for App Metrics core configuration. + /// + /// + /// An instance used to configure core App Metrics options. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder Configure(MetricsOptions options) + { + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + _setupAction(options); + + return _metricsBuilder; + } + + /// + /// + /// Uses the specifed key value pairs to configure an instance for App Metrics core configuration. + /// + /// + /// Keys match the s property names. + /// + /// + /// Key value pairs for configuring App Metrics + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder Configure(IEnumerable> optionValues) + { + if (optionValues == null) + { + throw new ArgumentNullException(nameof(optionValues)); + } + + var options = new KeyValuePairMetricsOptions(optionValues).AsOptions(); + + _setupAction(options); + + AddDefaultTags(options); + + return _metricsBuilder; + } + + /// + /// + /// Uses the specifed key value pairs to configure an instance for App Metrics core configuration. + /// + /// + /// Keys match the s property names. Any make key will override the value configured. + /// + /// + /// An instance used to configure core App Metrics options. + /// Key value pairs for configuring App Metrics + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder Configure(MetricsOptions options, IEnumerable> optionValues) + { + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + if (optionValues == null) + { + throw new ArgumentNullException(nameof(optionValues)); + } + + _setupAction(new KeyValuePairMetricsOptions(options, optionValues).AsOptions()); + + AddDefaultTags(options); + + return _metricsBuilder; + } + + /// + /// + /// Uses the specifed key value pairs to configure an instance for App Metrics core configuration. + /// + /// + /// Keys match the s property names. Any make key will override the value configured. + /// + /// + /// An setup action used to configure core App Metrics options. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder Configure(Action setupAction) + { + if (setupAction == null) + { + throw new ArgumentNullException(nameof(setupAction)); + } + + var options = new MetricsOptions(); + + setupAction(options); + + _setupAction(options); + + AddDefaultTags(options); + + return _metricsBuilder; + } + + private void AddDefaultTags(MetricsOptions options) + { + if (!options.AddDefaultGlobalTags) + { + return; + } + + var environmentInfo = _environmentInfoProvider.Build(); + + if (!options.GlobalTags.ContainsKey("app")) + { + options.GlobalTags.Add("app", environmentInfo.EntryAssemblyName); + } + + if (!options.GlobalTags.ContainsKey("server")) + { + options.GlobalTags.Add("server", environmentInfo.MachineName); + } + + if (!options.GlobalTags.ContainsKey("env")) + { +#if DEBUG + options.GlobalTags.Add("env", "debug"); +#else + options.GlobalTags.Add("env", "release"); +#endif + } + } + } +} diff --git a/src/App.Metrics.Core/Builder/MetricsOutputFormattingBuilder.cs b/src/App.Metrics.Core/Builder/MetricsOutputFormattingBuilder.cs new file mode 100644 index 00000000..dd712431 --- /dev/null +++ b/src/App.Metrics.Core/Builder/MetricsOutputFormattingBuilder.cs @@ -0,0 +1,72 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System; +using App.Metrics.Formatters; + +// ReSharper disable CheckNamespace +namespace App.Metrics + // ReSharper restore CheckNamespace +{ + /// + /// Builder for configuring s used for formatting s when they are reported. + /// + public class MetricsOutputFormattingBuilder + { + private readonly IMetricsBuilder _metricsBuilder; + private readonly Action _metricsFormatter; + + internal MetricsOutputFormattingBuilder( + IMetricsBuilder metricsBuilder, + Action metricsFormatter) + { + _metricsBuilder = metricsBuilder ?? throw new ArgumentNullException(nameof(metricsBuilder)); + _metricsFormatter = metricsFormatter ?? throw new ArgumentNullException(nameof(metricsFormatter)); + } + + /// + /// + /// Uses the specifed as one of the available formatters when reporting metric values. + /// + /// + /// Mulitple formatters can be used, in which case the will be set to the first configured formatter. + /// + /// + /// An instance used to format metric values when reporting. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder Using(IMetricsOutputFormatter formatter) + { + if (formatter == null) + { + throw new ArgumentNullException(nameof(formatter)); + } + + _metricsFormatter(formatter); + + return _metricsBuilder; + } + + /// + /// + /// Uses the specifed as one of the available formatters when reporting metric values. + /// + /// + /// Mulitple formatters can be used, in which case the will be set to the first configured formatter. + /// + /// + /// An type used to format metric values when reporting. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder Using() + where TMetricsOutputFormatter : IMetricsOutputFormatter, new() + { + _metricsFormatter(new TMetricsOutputFormatter()); + + return _metricsBuilder; + } + } +} diff --git a/src/App.Metrics.Core/Builder/MetricsReservoirSamplingBuilder.cs b/src/App.Metrics.Core/Builder/MetricsReservoirSamplingBuilder.cs new file mode 100644 index 00000000..c7ba1832 --- /dev/null +++ b/src/App.Metrics.Core/Builder/MetricsReservoirSamplingBuilder.cs @@ -0,0 +1,281 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System; +using App.Metrics.ReservoirSampling; +using App.Metrics.ReservoirSampling.ExponentialDecay; +using App.Metrics.ReservoirSampling.SlidingWindow; +using App.Metrics.ReservoirSampling.Uniform; +using App.Metrics.Scheduling; + +// ReSharper disable CheckNamespace +namespace App.Metrics + // ReSharper restore CheckNamespace +{ + /// + /// Builder for configuring sampling using an . + /// + public class MetricsReservoirSamplingBuilder + { + private readonly Action _defaultReservoir; + private readonly IMetricsBuilder _metricsBuilder; + + internal MetricsReservoirSamplingBuilder( + IMetricsBuilder metricsBuilder, + Action defaultReservoir) + { + _metricsBuilder = metricsBuilder ?? throw new ArgumentNullException(nameof(metricsBuilder)); + _defaultReservoir = defaultReservoir ?? throw new ArgumentNullException(nameof(defaultReservoir)); + } + + /// + /// + /// Uses the reservoir for s which require + /// sampling. + /// + /// + /// A histogram with a uniform reservoir produces + /// quantiles + /// which are valid for the entirely of the histogram’s lifetime. + /// + /// + /// This sampling reservoir can be used when you are interested in long-term measurements, it does not offer a + /// sence of recency. + /// + /// + /// All samples are equally likely to be evicted when the reservoir is at full capacity. + /// + /// + /// The number of samples to keep in the sampling reservoir. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder AlgorithmR(int sampleSize) + { + Reservoir(() => new DefaultAlgorithmRReservoir(sampleSize)); + + return _metricsBuilder; + } + + /// + /// + /// Uses the reservoir for s which require + /// sampling. + /// + /// + /// A histogram with a uniform reservoir produces + /// quantiles + /// which are valid for the entirely of the histogram’s lifetime. + /// + /// + /// This sampling reservoir can be used when you are interested in long-term measurements, it does not offer a + /// sence of recency. + /// + /// + /// All samples are equally likely to be evicted when the reservoir is at full capacity. + /// + /// + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder AlgorithmR() + { + Reservoir(); + + return _metricsBuilder; + } + + /// + /// + /// Uses the reservoir for s which + /// require sampling. + /// A histogram with an exponentially decaying reservoir produces + /// quantiles which are representative of (roughly) the + /// last five minutes of data. + /// + /// + /// The reservoir is produced by using a + /// forward-decaying reservoir with an + /// exponential weighty towards recent data unlike a Uniform Reservoir which does not provide a sense of recency. + /// + /// + /// This sampling reservoir can be used when you are interested in recent changes to the distribution of data + /// rather than a median on the lifetime of the histgram. + /// + /// + /// The number of samples to keep in the sampling reservoir. + /// + /// The alpha value, e.g 0.015 will heavily biases the reservoir to the past 5 mins of measurements. The higher the + /// value the more biased the reservoir will be towards newer values. + /// + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder ForwardDecaying(int sampleSize, double alpha) + { + Reservoir(() => new DefaultForwardDecayingReservoir(sampleSize, alpha)); + + return _metricsBuilder; + } + + /// + /// + /// Uses the reservoir for s which + /// require sampling. + /// A histogram with an exponentially decaying reservoir produces + /// quantiles which are representative of (roughly) the + /// last five minutes of data. + /// + /// + /// The reservoir is produced by using a + /// forward-decaying reservoir with an + /// exponential weighty towards recent data unlike a Uniform Reservoir which does not provide a sense of recency. + /// + /// + /// This sampling reservoir can be used when you are interested in recent changes to the distribution of data + /// rather than a median on the lifetime of the histgram. + /// + /// + /// The number of samples to keep in the sampling reservoir. + /// + /// The alpha value, e.g 0.015 will heavily biases the reservoir to the past 5 mins of measurements. The higher the + /// value the more biased the reservoir will be towards newer values. + /// + /// The used for timing. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder ForwardDecaying(int sampleSize, double alpha, IClock clock) + { + Reservoir(() => new DefaultForwardDecayingReservoir(sampleSize, alpha, clock)); + + return _metricsBuilder; + } + + /// + /// + /// Uses the reservoir for s which + /// require sampling. + /// A histogram with an exponentially decaying reservoir produces + /// quantiles which are representative of (roughly) the + /// last five minutes of data. + /// + /// + /// The reservoir is produced by using a + /// forward-decaying reservoir with an + /// exponential weighty towards recent data unlike a Uniform Reservoir which does not provide a sense of recency. + /// + /// + /// This sampling reservoir can be used when you are interested in recent changes to the distribution of data + /// rather than a median on the lifetime of the histgram. + /// + /// + /// The number of samples to keep in the sampling reservoir. + /// + /// The alpha value, e.g 0.015 will heavily biases the reservoir to the past 5 mins of measurements. The higher the + /// value the more biased the reservoir will be towards newer values. + /// + /// The used for timing. + /// The used to rescale the reservoir. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder ForwardDecaying(int sampleSize, double alpha, IClock clock, IScheduler rescaleScheduler) + { + Reservoir(() => new DefaultForwardDecayingReservoir(sampleSize, alpha, clock, rescaleScheduler)); + + return _metricsBuilder; + } + + /// + /// + /// Uses the reservoir for s which + /// require sampling. + /// A histogram with an exponentially decaying reservoir produces + /// quantiles which are representative of (roughly) the + /// last five minutes of data. + /// + /// + /// The reservoir is produced by using a + /// forward-decaying reservoir with an + /// exponential weighty towards recent data unlike a Uniform Reservoir which does not provide a sense of recency. + /// + /// + /// This samling reservoir can be used when you are interested in recent changes to the distribution of data + /// rather than a median on the lifetime of the histgram. + /// + /// + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder ForwardDecaying() + { + Reservoir(); + + return _metricsBuilder; + } + + /// + /// Uses the specifed for s which require sampling. + /// + /// + /// An function used to sample metrics. + /// + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder Reservoir(Func reservoirBuilder) + { + _defaultReservoir(new DefaultSamplingReservoirProvider(reservoirBuilder)); + + return _metricsBuilder; + } + + /// + /// Uses the specifed for s which require sampling. + /// + /// An type used to sample metrics. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder Reservoir() + where TReservoir : class, IReservoir, new() + { + _defaultReservoir(new DefaultSamplingReservoirProvider(() => new TReservoir())); + + return _metricsBuilder; + } + + /// + /// Uses reservoir sample for s which + /// require sampling. A Reservoir implementation backed by a sliding window that stores only the measurements made in + /// the last N seconds (or other time unit). + /// + /// The number of samples to keep in the sampling reservoir. + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder SlidingWindow(int sampleSize) + { + Reservoir(() => new DefaultSlidingWindowReservoir(sampleSize)); + + return _metricsBuilder; + } + + /// + /// Uses reservoir sample for s which + /// require sampling. A Reservoir implementation backed by a sliding window that stores only the measurements made in + /// the last N seconds (or other time unit). + /// + /// + /// An that can be used to further configure the App Metrics. + /// + public IMetricsBuilder SlidingWindow() + { + Reservoir(); + + return _metricsBuilder; + } + } +} \ No newline at end of file diff --git a/src/App.Metrics.Core/DependencyInjection/IMetricsBuilder.cs b/src/App.Metrics.Core/DependencyInjection/IMetricsBuilder.cs deleted file mode 100644 index d9760f2a..00000000 --- a/src/App.Metrics.Core/DependencyInjection/IMetricsBuilder.cs +++ /dev/null @@ -1,19 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -// ReSharper disable CheckNamespace -namespace Microsoft.Extensions.DependencyInjection - // ReSharper restore CheckNamespace -{ - /// - /// An interface for configuring App Metrics services. - /// - public interface IMetricsBuilder - { - /// - /// Gets the where App Metrics services are configured. - /// - IServiceCollection Services { get; } - } -} \ No newline at end of file diff --git a/src/App.Metrics.Core/DependencyInjection/IMetricsCoreBuilder.cs b/src/App.Metrics.Core/DependencyInjection/IMetricsCoreBuilder.cs deleted file mode 100644 index 1495f860..00000000 --- a/src/App.Metrics.Core/DependencyInjection/IMetricsCoreBuilder.cs +++ /dev/null @@ -1,19 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -// ReSharper disable CheckNamespace -namespace Microsoft.Extensions.DependencyInjection - // ReSharper restore CheckNamespace -{ - /// - /// An interface for configuring essential App Metrics services. - /// - public interface IMetricsCoreBuilder - { - /// - /// Gets the where Metrics services are configured. - /// - IServiceCollection Services { get; } - } -} \ No newline at end of file diff --git a/src/App.Metrics.Core/DependencyInjection/Internal/AppMetricsServicesHelper.cs b/src/App.Metrics.Core/DependencyInjection/Internal/AppMetricsServicesHelper.cs deleted file mode 100644 index d84811f4..00000000 --- a/src/App.Metrics.Core/DependencyInjection/Internal/AppMetricsServicesHelper.cs +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using Microsoft.Extensions.DependencyInjection; - -namespace App.Metrics.DependencyInjection.Internal -{ - [ExcludeFromCodeCoverage] - public static class AppMetricsServicesHelper - { - private static readonly string InvalidOperationExceptionMessage = - "Unable to find the App Metrics required services. Please add all required services by calling IServiceCollection.AddMetrics(); or equivalent"; - - /// - /// Throws InvalidOperationException when MetricsMarkerService is not present - /// in the list of services. - /// - /// The list of services. - public static void ThrowIfMetricsNotRegistered(IServiceProvider services) - { - if (services.GetService(typeof(AppMetricsMarkerService)) == null) - { - throw new InvalidOperationException(InvalidOperationExceptionMessage); - } - } - - /// - /// Throws InvalidOperationException when MetricsMarkerService is not present - /// in the list of services. - /// - /// The list of services. - public static void ThrowIfMetricsNotRegistered(IServiceCollection services) - { - if (services.All(s => s.ServiceType != typeof(AppMetricsMarkerService))) - { - throw new InvalidOperationException(InvalidOperationExceptionMessage); - } - } - } -} \ No newline at end of file diff --git a/src/App.Metrics.Core/DependencyInjection/MetricsCoreMetricsBuilderExtensions.cs b/src/App.Metrics.Core/DependencyInjection/MetricsCoreMetricsBuilderExtensions.cs deleted file mode 100644 index 4e1d3bcd..00000000 --- a/src/App.Metrics.Core/DependencyInjection/MetricsCoreMetricsBuilderExtensions.cs +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -using System; -using App.Metrics; - -// ReSharper disable CheckNamespace -namespace Microsoft.Extensions.DependencyInjection - // ReSharper restore CheckNamespace -{ - public static class MetricsCoreMetricsBuilderExtensions - { - /// - /// Registers an action to configure . - /// - /// The . - /// An . - /// The instance. - public static IMetricsBuilder AddMetricsOptions( - this IMetricsBuilder builder, - Action setupAction) - { - if (builder == null) - { - throw new ArgumentNullException(nameof(builder)); - } - - if (setupAction == null) - { - throw new ArgumentNullException(nameof(setupAction)); - } - - builder.Services.Configure(setupAction); - - return builder; - } - } -} \ No newline at end of file diff --git a/src/App.Metrics.Core/DependencyInjection/MetricsCoreMetricsCoreBuilderExtensions.cs b/src/App.Metrics.Core/DependencyInjection/MetricsCoreMetricsCoreBuilderExtensions.cs deleted file mode 100644 index bc9d05f6..00000000 --- a/src/App.Metrics.Core/DependencyInjection/MetricsCoreMetricsCoreBuilderExtensions.cs +++ /dev/null @@ -1,80 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -using System; -using App.Metrics; -using App.Metrics.Filters; -using App.Metrics.ReservoirSampling; -using Microsoft.Extensions.DependencyInjection.Extensions; - -// ReSharper disable CheckNamespace -namespace Microsoft.Extensions.DependencyInjection - // ReSharper restore CheckNamespace -{ - /// - /// Extensions for configuring App Metrics using an . - /// - public static class MetricsCoreMetricsCoreBuilderExtensions - { - public static IMetricsCoreBuilder AddClockType(this IMetricsCoreBuilder builder) - where T : class, IClock, new() - { - var destriptor = ServiceDescriptor.Singleton(new T()); - - builder.Services.Replace(destriptor); - - return builder; - } - - /// - /// Adds the default reservoir which will be applied to all metrics using sampling that do not have an - /// set explicitly. - /// - /// The metrics host builder. - /// The reservoir builder to use as the default reservoir for sampling. - /// The same instance of the metrics host builder. - public static IMetricsCoreBuilder AddDefaultReservoir(this IMetricsCoreBuilder builder, Func reservoirBuilder) - { - var descriptor = ServiceDescriptor.Singleton(new DefaultSamplingReservoirProvider(reservoirBuilder)); - - builder.Services.Replace(descriptor); - - return builder; - } - - public static IMetricsCoreBuilder AddGlobalFilter(this IMetricsCoreBuilder builder, IFilterMetrics filter) - { - var descripter = ServiceDescriptor.Singleton(filter); - - builder.Services.Replace(descripter); - - return builder; - } - - /// - /// Registers an action to configure . - /// - /// The . - /// An . - /// The instance. - public static IMetricsCoreBuilder AddMetricsOptions( - this IMetricsCoreBuilder builder, - Action setupAction) - { - if (builder == null) - { - throw new ArgumentNullException(nameof(builder)); - } - - if (setupAction == null) - { - throw new ArgumentNullException(nameof(setupAction)); - } - - builder.Services.Configure(setupAction); - - return builder; - } - } -} \ No newline at end of file diff --git a/src/App.Metrics.Core/DependencyInjection/MetricsCoreServiceCollectionExtensions.cs b/src/App.Metrics.Core/DependencyInjection/MetricsCoreServiceCollectionExtensions.cs deleted file mode 100644 index c5ebeabe..00000000 --- a/src/App.Metrics.Core/DependencyInjection/MetricsCoreServiceCollectionExtensions.cs +++ /dev/null @@ -1,200 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -using System; -using App.Metrics; -using App.Metrics.DependencyInjection.Internal; -using App.Metrics.Filtering; -using App.Metrics.Filters; -using App.Metrics.Infrastructure; -using App.Metrics.Internal; -using App.Metrics.Internal.NoOp; -using App.Metrics.Registry; -using App.Metrics.ReservoirSampling; -using App.Metrics.Tagging; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Options; - -// ReSharper disable CheckNamespace -namespace Microsoft.Extensions.DependencyInjection - // ReSharper restore CheckNamespace -{ - /// - /// Extension methods for setting up essential App Metrics services in an . - /// - public static class MetricsCoreServiceCollectionExtensions - { - /// - /// Adds essential App Metrics services to the specified . - /// - /// The to add services to. - /// - /// An that can be used to further configure the App Metrics services. - /// - public static IMetricsCoreBuilder AddMetricsCore(this IServiceCollection services) - { - AddMetricsCoreServices(services); - - var builder = new MetricsCoreBuilder(services); - - return builder; - } - - /// - /// Adds essential App Metrics services and configuration to the specified . - /// - /// The to add services to. - /// - /// The from where to load . - /// - /// - /// An that can be used to further configure the App Metrics services. - /// - public static IMetricsCoreBuilder AddMetricsCore(this IServiceCollection services, IConfiguration configuration) - { - var builder = services.AddMetricsCore(); - - services.Configure(configuration); - - return builder; - } - - /// - /// Adds essential App Metrics services and configuration to the specified . - /// - /// The to add services to. - /// - /// An to configure the provided . - /// - /// - /// The from where to load . - /// - /// - /// An that can be used to further configure the App Metrics services. - /// - public static IMetricsCoreBuilder AddMetricsCore( - this IServiceCollection services, - Action setupAction, - IConfiguration configuration) - { - var builder = services.AddMetricsCore(); - - services.Configure(setupAction); - services.Configure(configuration); - - return builder; - } - - /// - /// Adds essential App Metrics services and configuration to the specified . - /// - /// The to add services to. - /// - /// The from where to load . - /// - /// - /// An to configure the provided . - /// - /// - /// An that can be used to further configure the App Metrics services. - /// - public static IMetricsCoreBuilder AddMetricsCore( - this IServiceCollection services, - IConfiguration configuration, - Action setupAction) - { - var builder = services.AddMetricsCore(); - - services.Configure(configuration); - services.Configure(setupAction); - - return builder; - } - - /// - /// Adds essential App Metrics services and configuration to the specified . - /// - /// The to add services to. - /// - /// An to configure the provided . - /// - /// - /// An that can be used to further configure the App Metrics services. - /// - public static IMetricsCoreBuilder AddMetricsCore(this IServiceCollection services, Action setupAction) - { - var builder = services.AddMetricsCore(); - - services.Configure(setupAction); - - return builder; - } - - internal static void AddMetricsCoreServices(IServiceCollection services) - { - // - // Options - // - services.AddOptions(); - services.TryAddEnumerable( - ServiceDescriptor.Transient, MetricsCoreMetricsOptionsSetup>()); - - // - // Metrics Registry - // - services.TryAddTransient>( - provider => - { - var optionsAccessor = provider.GetRequiredService>(); - var globalTags = optionsAccessor.Value.GlobalTags; - - return context => new DefaultMetricContextRegistry(context, new GlobalMetricTags(globalTags)); - }); - - services.TryAddSingleton( - provider => - { - var optionsAccessor = provider.GetRequiredService>(); - - if (!optionsAccessor.Value.MetricsEnabled) - { - return new NullMetricsRegistry(); - } - - var clock = provider.GetRequiredService(); - var newContextRegistry = provider.GetRequiredService>(); - - return new DefaultMetricsRegistry(optionsAccessor, clock, newContextRegistry); - }); - - // - // Sampling - // - services.TryAddSingleton(provider => new DefaultSamplingReservoirProvider()); - - // - // Filtering - // - services.TryAddSingleton(); - - // - // Metrics - // - services.TryAddSingleton(); - services.TryAddSingleton(); - services.TryAddSingleton(); - services.TryAddSingleton(); - services.TryAddSingleton(); - services.TryAddSingleton(); - - // - // Random Infrasturcture - // - services.TryAddSingleton(); - services.TryAddSingleton(); - services.TryAddSingleton(provider => new StopwatchClock()); - } - } -} \ No newline at end of file diff --git a/src/App.Metrics.Core/IMetricsRoot.cs b/src/App.Metrics.Core/IMetricsRoot.cs new file mode 100644 index 00000000..40c4c00b --- /dev/null +++ b/src/App.Metrics.Core/IMetricsRoot.cs @@ -0,0 +1,49 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using App.Metrics.Formatters; +using App.Metrics.Infrastructure; + +namespace App.Metrics +{ + public interface IMetricsRoot : IMetrics + { + /// + /// Gets a list of s that are used by this application to format metric + /// results. + /// + /// + /// A list of s that are used by this application. + /// + MetricsFormatterCollection OutputMetricsFormatters { get; } + + /// + /// Gets the default to use when metrics are attempted to be formatted. + /// + /// + /// The default s that is used by this application. + /// + IMetricsOutputFormatter DefaultOutputMetricsFormatter { get; } + + /// + /// Gets the default to use when the environment's info is attempted to be formatted. + /// + /// + /// The default s that is used by this application. + /// + IEnvOutputFormatter DefaultOutputEnvFormatter { get; } + + /// + /// Gets a list of s that are used by this application to format environment info. + /// + /// + /// A list of s that are used by this application. + /// + EnvFormatterCollection OutputEnvFormatters { get; } + + MetricsOptions Options { get; } + + EnvironmentInfo EnvironmentInfo { get; } + } +} \ No newline at end of file diff --git a/src/App.Metrics.Core/Infrastructure/AppMetricsEnvironment.cs b/src/App.Metrics.Core/Infrastructure/AppMetricsEnvironment.cs deleted file mode 100644 index 160ae099..00000000 --- a/src/App.Metrics.Core/Infrastructure/AppMetricsEnvironment.cs +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -using System; -using System.Reflection; -using System.Runtime.Versioning; - -// ReSharper disable CheckNamespace -namespace App.Metrics - // ReSharper restore CheckNamespace -{ - public sealed class AppMetricsEnvironment : IAppMetricsEnvironment - { - public AppMetricsEnvironment() - { - var entryAssembly = Assembly.GetEntryAssembly(); - ApplicationName = AppDomain.CurrentDomain?.FriendlyName ?? "unknown"; - ApplicationVersion = entryAssembly?.GetName()?.Version.ToString() ?? "1.0.0.0"; - RuntimeFramework = entryAssembly?.GetCustomAttribute()?.FrameworkDisplayName ?? "unknown"; - RuntimeFrameworkVersion = entryAssembly?.GetCustomAttribute()?.FrameworkName ?? "unknown"; - } - - public string ApplicationName { get; } - - public string ApplicationVersion { get; } - - public string RuntimeFramework { get; } - - public string RuntimeFrameworkVersion { get; } - } -} \ No newline at end of file diff --git a/src/App.Metrics.Core/Infrastructure/EnvironmentInfoProvider.cs b/src/App.Metrics.Core/Infrastructure/EnvironmentInfoProvider.cs index 6381fa12..b5cbdad3 100644 --- a/src/App.Metrics.Core/Infrastructure/EnvironmentInfoProvider.cs +++ b/src/App.Metrics.Core/Infrastructure/EnvironmentInfoProvider.cs @@ -17,14 +17,12 @@ public EnvironmentInfo Build() EnvironmentInfoProviderCache.Instance.FrameworkDescription, EnvironmentInfoProviderCache.Instance.EntryAssemblyName, EnvironmentInfoProviderCache.Instance.EntryAssemblyVersion, - EnvironmentInfoProviderCache.Instance.HostName, localTimeString, EnvironmentInfoProviderCache.Instance.MachineName, EnvironmentInfoProviderCache.Instance.OperatingSystemPlatform, EnvironmentInfoProviderCache.Instance.OperatingSystemVersion, EnvironmentInfoProviderCache.Instance.OperatingSystemArchitecture, EnvironmentInfoProviderCache.Instance.ProcessArchitecture, - EnvironmentInfoProviderCache.Instance.ProcessName, EnvironmentInfoProviderCache.Instance.ProcessorCount); } } diff --git a/src/App.Metrics.Core/Infrastructure/EnvironmentInfoProviderCache.cs b/src/App.Metrics.Core/Infrastructure/EnvironmentInfoProviderCache.cs index 80d907c7..f3460610 100644 --- a/src/App.Metrics.Core/Infrastructure/EnvironmentInfoProviderCache.cs +++ b/src/App.Metrics.Core/Infrastructure/EnvironmentInfoProviderCache.cs @@ -3,8 +3,6 @@ // using System; -using System.Diagnostics; -using System.Net; using System.Reflection; using System.Runtime.InteropServices; @@ -14,17 +12,14 @@ internal class EnvironmentInfoProviderCache { private EnvironmentInfoProviderCache() { - var process = Process.GetCurrentProcess(); var platform = GetOSPlatform(); - ProcessName = StringExtensions.GetSafeString(() => process.ProcessName); ProcessArchitecture = StringExtensions.GetSafeString(() => RuntimeInformation.ProcessArchitecture.ToString()); OperatingSystemVersion = StringExtensions.GetSafeString(() => RuntimeInformation.OSDescription); OperatingSystemPlatform = StringExtensions.GetSafeString(() => platform.ToString()); OperatingSystemArchitecture = StringExtensions.GetSafeString(() => RuntimeInformation.OSArchitecture.ToString()); ProcessorCount = StringExtensions.GetSafeString(() => Environment.ProcessorCount.ToString()); MachineName = StringExtensions.GetSafeString(() => Environment.MachineName); - HostName = StringExtensions.GetSafeString(Dns.GetHostName); FrameworkDescription = StringExtensions.GetSafeString(() => RuntimeInformation.FrameworkDescription); var entryAssembly = Assembly.GetEntryAssembly(); @@ -39,8 +34,6 @@ private EnvironmentInfoProviderCache() public string EntryAssemblyVersion { get; } - public string HostName { get; } - public string MachineName { get; } public string OperatingSystemVersion { get; } @@ -49,8 +42,6 @@ private EnvironmentInfoProviderCache() public string OperatingSystemArchitecture { get; } - public string ProcessName { get; } - public string ProcessorCount { get; } public string ProcessArchitecture { get; } diff --git a/src/App.Metrics.Core/Internal/AppMetricsTaskHelper.cs b/src/App.Metrics.Core/Internal/AppMetricsTaskHelper.cs new file mode 100644 index 00000000..32950738 --- /dev/null +++ b/src/App.Metrics.Core/Internal/AppMetricsTaskHelper.cs @@ -0,0 +1,23 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +#if !NETSTANDARD1_3 + +using System.Threading.Tasks; + +namespace App.Metrics.Internal +{ + public static class AppMetricsTaskHelper + { + private static Task _completedTask; + + private struct VoidTaskResult { } + + public static Task CompletedTask() + { + return _completedTask ?? (_completedTask = Task.FromResult(default(VoidTaskResult))); + } + } +} +#endif \ No newline at end of file diff --git a/src/App.Metrics.Core/Internal/DefaultMetrics.cs b/src/App.Metrics.Core/Internal/DefaultMetrics.cs index ea1c4824..f16d1010 100644 --- a/src/App.Metrics.Core/Internal/DefaultMetrics.cs +++ b/src/App.Metrics.Core/Internal/DefaultMetrics.cs @@ -15,9 +15,7 @@ namespace App.Metrics.Internal /// This is the entry point to the application's metrics registry /// /// - // ReSharper disable ClassNeverInstantiated.Global public sealed class DefaultMetrics : IMetrics - // ReSharper restore ClassNeverInstantiated.Global { /// /// Initializes a new instance of the class. diff --git a/src/App.Metrics.Core/Internal/DefaultMetricsBuilderFactory.cs b/src/App.Metrics.Core/Internal/DefaultMetricsBuilderFactory.cs index 94c3b1fa..09109bc6 100644 --- a/src/App.Metrics.Core/Internal/DefaultMetricsBuilderFactory.cs +++ b/src/App.Metrics.Core/Internal/DefaultMetricsBuilderFactory.cs @@ -12,19 +12,22 @@ namespace App.Metrics.Internal { - // ReSharper disable ClassNeverInstantiated.Global public sealed class DefaultMetricsBuilderFactory : IBuildMetrics - // ReSharper restore ClassNeverInstantiated.Global { - public DefaultMetricsBuilderFactory() + // Internal for testing +#pragma warning disable SA1401 // Fields must be private + internal readonly DefaultSamplingReservoirProvider DefaultSamplingReservoir; +#pragma warning restore SA1401 // Fields must be private + + public DefaultMetricsBuilderFactory(DefaultSamplingReservoirProvider defaultSamplingReservoir) { - var defaultReservoir = new DefaultSamplingReservoirProvider(); - Apdex = new DefaultApdexBuilder(defaultReservoir); + DefaultSamplingReservoir = defaultSamplingReservoir; + Apdex = new DefaultApdexBuilder(defaultSamplingReservoir); Counter = new DefaultCounterBuilder(); Gauge = new DefaultGaugeBuilder(); - Histogram = new DefaultHistogramBuilder(defaultReservoir); + Histogram = new DefaultHistogramBuilder(defaultSamplingReservoir); Meter = new DefaultMeterBuilder(); - Timer = new DefaultTimerBuilder(defaultReservoir); + Timer = new DefaultTimerBuilder(defaultSamplingReservoir); } /// diff --git a/src/App.Metrics.Core/Internal/DefaultMetricsRegistry.cs b/src/App.Metrics.Core/Internal/DefaultMetricsRegistry.cs index fea69040..9579f6ec 100644 --- a/src/App.Metrics.Core/Internal/DefaultMetricsRegistry.cs +++ b/src/App.Metrics.Core/Internal/DefaultMetricsRegistry.cs @@ -15,7 +15,6 @@ using App.Metrics.Meter; using App.Metrics.Registry; using App.Metrics.Timer; -using Microsoft.Extensions.Options; namespace App.Metrics.Internal { @@ -29,13 +28,13 @@ public sealed class DefaultMetricsRegistry : IMetricsRegistry private readonly Lazy _nullMetricsRegistry = new Lazy(); public DefaultMetricsRegistry( - IOptions options, + string defaultContextLabel, IClock clock, Func newContextRegistry) { _clock = clock; _newContextRegistry = newContextRegistry; - _defaultContextLabel = options.Value.DefaultContextLabel; + _defaultContextLabel = defaultContextLabel; _contexts.TryAdd(_defaultContextLabel, newContextRegistry(_defaultContextLabel)); } diff --git a/src/App.Metrics.Core/Internal/ExcludeFromCodeCoverageAttribute.cs b/src/App.Metrics.Core/Internal/ExcludeFromCodeCoverageAttribute.cs new file mode 100644 index 00000000..228771b0 --- /dev/null +++ b/src/App.Metrics.Core/Internal/ExcludeFromCodeCoverageAttribute.cs @@ -0,0 +1,14 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +#if NETSTANDARD1_1 || NETSTANDARD1_3 || NETSTANDARD1_6 + +// ReSharper disable CheckNamespace +namespace System.Diagnostics.CodeAnalysis + // ReSharper restore CheckNamespace +{ + internal class ExcludeFromCodeCoverageAttribute : Attribute { } +} + +#endif diff --git a/src/App.Metrics.Core/DependencyInjection/Internal/AppMetricsMarkerService.cs b/src/App.Metrics.Core/Internal/Infrastructure/AppMetricsMarkerService.cs similarity index 87% rename from src/App.Metrics.Core/DependencyInjection/Internal/AppMetricsMarkerService.cs rename to src/App.Metrics.Core/Internal/Infrastructure/AppMetricsMarkerService.cs index f052439b..9c678cd8 100644 --- a/src/App.Metrics.Core/DependencyInjection/Internal/AppMetricsMarkerService.cs +++ b/src/App.Metrics.Core/Internal/Infrastructure/AppMetricsMarkerService.cs @@ -2,7 +2,7 @@ // Copyright (c) Allan Hardy. All rights reserved. // -namespace App.Metrics.DependencyInjection.Internal +namespace App.Metrics.Internal.Infrastructure { /// /// This is a Marker class which is used to determine if all the services were added diff --git a/src/App.Metrics.Core/Internal/MetricsBuilder.cs b/src/App.Metrics.Core/Internal/MetricsBuilder.cs deleted file mode 100644 index 16866a7d..00000000 --- a/src/App.Metrics.Core/Internal/MetricsBuilder.cs +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -using System; -using Microsoft.Extensions.DependencyInjection; - -namespace App.Metrics.Internal -{ - public class MetricsBuilder : IMetricsBuilder - { - public MetricsBuilder(IServiceCollection services) - { - Services = services ?? throw new ArgumentNullException(nameof(services)); - } - - /// - public IServiceCollection Services { get; } - } -} \ No newline at end of file diff --git a/src/App.Metrics.Core/Internal/MetricsCoreBuilder.cs b/src/App.Metrics.Core/Internal/MetricsCoreBuilder.cs deleted file mode 100644 index d2e4fae9..00000000 --- a/src/App.Metrics.Core/Internal/MetricsCoreBuilder.cs +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -using System; -using Microsoft.Extensions.DependencyInjection; - -namespace App.Metrics.Internal -{ - public class MetricsCoreBuilder : IMetricsCoreBuilder - { - public MetricsCoreBuilder(IServiceCollection services) - { - Services = services ?? throw new ArgumentNullException(nameof(services)); - } - - /// - public IServiceCollection Services { get; } - } -} \ No newline at end of file diff --git a/src/App.Metrics.Core/Internal/MetricsCoreMetricsOptionsSetup.cs b/src/App.Metrics.Core/Internal/MetricsCoreMetricsOptionsSetup.cs deleted file mode 100644 index d6a3b72e..00000000 --- a/src/App.Metrics.Core/Internal/MetricsCoreMetricsOptionsSetup.cs +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -using App.Metrics.Infrastructure; -using Microsoft.Extensions.Options; - -namespace App.Metrics.Internal -{ - /// - /// Sets up default options for . - /// - public class MetricsCoreMetricsOptionsSetup : IConfigureOptions - { - private readonly EnvironmentInfo _environmentInfo; - - public MetricsCoreMetricsOptionsSetup(EnvironmentInfoProvider environmentInfoProvider) - { - _environmentInfo = environmentInfoProvider.Build(); - } - - /// - public void Configure(MetricsOptions options) - { - if (options.AddDefaultGlobalTags) - { - AddDefaultTags(options); - } - } - - private void AddDefaultTags(MetricsOptions options) - { - if (!options.GlobalTags.ContainsKey("app")) - { - options.GlobalTags.Add("app", _environmentInfo.EntryAssemblyName); - } - - if (!options.GlobalTags.ContainsKey("server")) - { - options.GlobalTags.Add("server", _environmentInfo.MachineName); - } - - if (!options.GlobalTags.ContainsKey("env")) - { -#if DEBUG - options.GlobalTags.Add("env", "debug"); -#else - options.GlobalTags.Add("env", "release"); -#endif - } - } - } -} \ No newline at end of file diff --git a/src/App.Metrics.Core/Internal/NoOp/NoOpMetrics.cs b/src/App.Metrics.Core/Internal/NoOp/NoOpMetrics.cs new file mode 100644 index 00000000..5846bdbf --- /dev/null +++ b/src/App.Metrics.Core/Internal/NoOp/NoOpMetrics.cs @@ -0,0 +1,32 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using App.Metrics.Filtering; +using App.Metrics.Filters; +using App.Metrics.Infrastructure; +using App.Metrics.Registry; +using App.Metrics.ReservoirSampling; +using App.Metrics.ReservoirSampling.ExponentialDecay; + +namespace App.Metrics.Internal.NoOp +{ + internal class NoOpMetrics : IMetrics + { + private static readonly IMetricsRegistry Registry = new NullMetricsRegistry(); + + public IBuildMetrics Build => new DefaultMetricsBuilderFactory(new DefaultSamplingReservoirProvider(() => new DefaultForwardDecayingReservoir())); + + public IClock Clock => new StopwatchClock(); + + public IFilterMetrics Filter => new NoOpMetricsFilter(); + + public IManageMetrics Manage => new DefaultMetricsManager(Registry); + + public IMeasureMetrics Measure => new DefaultMeasureMetricsProvider(Registry, Build, Clock); + + public IProvideMetrics Provider => new DefaultMetricsProvider(Registry, Build, Clock); + + public IProvideMetricValues Snapshot => new DefaultMetricValuesProvider(Filter, Registry); + } +} \ No newline at end of file diff --git a/src/App.Metrics.Core/KeyValuePairMetricsOptions.cs b/src/App.Metrics.Core/KeyValuePairMetricsOptions.cs new file mode 100644 index 00000000..05ccb366 --- /dev/null +++ b/src/App.Metrics.Core/KeyValuePairMetricsOptions.cs @@ -0,0 +1,98 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System; +using System.Collections.Generic; +using System.Linq; +using App.Metrics.Tagging; + +namespace App.Metrics +{ + internal class KeyValuePairMetricsOptions + { + private const string AddDefaultGlobalTagsDirective = nameof(MetricsOptions.AddDefaultGlobalTags); + private const string DefaultContextLabelDirective = nameof(MetricsOptions.DefaultContextLabel); + private const string GlobalTagsDirective = nameof(MetricsOptions.GlobalTags); + private const string MetricsEnabledDirective = nameof(MetricsOptions.MetricsEnabled); + private readonly MetricsOptions _options; + + private readonly Dictionary _optionValues; + + public KeyValuePairMetricsOptions(MetricsOptions options, IEnumerable> optionValues) + { + if (optionValues == null) + { + throw new ArgumentNullException(nameof(optionValues)); + } + + _options = options ?? throw new ArgumentNullException(nameof(options)); + + _optionValues = optionValues.ToDictionary(o => o.Key, o => o.Value); + } + + public KeyValuePairMetricsOptions(IEnumerable> options) + { + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + _optionValues = options.ToDictionary(o => o.Key, o => o.Value); + } + + public MetricsOptions AsOptions() + { + var options = _options ?? new MetricsOptions(); + + foreach (var key in _optionValues.Keys) + { + if (string.Compare(key, DefaultContextLabelDirective, StringComparison.CurrentCultureIgnoreCase) == 0) + { + options.DefaultContextLabel = _optionValues[key]; + } + else if (string.Compare(key, AddDefaultGlobalTagsDirective, StringComparison.CurrentCultureIgnoreCase) == 0) + { + if (!bool.TryParse(_optionValues[key], out var addDefaultGlobalTags)) + { + throw new InvalidCastException($"Attempted to bind {key} to {AddDefaultGlobalTagsDirective} but it's not a boolean"); + } + + options.AddDefaultGlobalTags = addDefaultGlobalTags; + } + else if (string.Compare(key, GlobalTagsDirective, StringComparison.CurrentCultureIgnoreCase) == 0) + { + options.GlobalTags = new GlobalMetricTags(); + + var globalTags = _optionValues[key].Split(new[] { ",", ", " }, StringSplitOptions.RemoveEmptyEntries); + + foreach (var tagKeyValue in globalTags) + { + var keyValue = tagKeyValue.Split('='); + + if (keyValue.Length != 2) + { + throw new InvalidOperationException( + $"Attempted to bind {key} to {GlobalTagsDirective} but the value was not property formatted, format as: value='tag1Name=tag1Value,tag2Name=tag2Value"); + } + + var tagKey = keyValue[0].Trim(); + var tagValue = keyValue[1].Trim(); + options.GlobalTags.Add(tagKey, tagValue); + } + } + else if (string.Compare(key, MetricsEnabledDirective, StringComparison.CurrentCultureIgnoreCase) == 0) + { + if (!bool.TryParse(_optionValues[key], out var metricsEnabled)) + { + throw new InvalidCastException($"Attempted to bind {key} to {MetricsEnabledDirective} but it's not a boolean"); + } + + options.MetricsEnabled = metricsEnabled; + } + } + + return options; + } + } +} \ No newline at end of file diff --git a/src/App.Metrics.Core/MetricsOptions.cs b/src/App.Metrics.Core/MetricsOptions.cs index 3039bec7..82c63dce 100644 --- a/src/App.Metrics.Core/MetricsOptions.cs +++ b/src/App.Metrics.Core/MetricsOptions.cs @@ -2,7 +2,6 @@ // Copyright (c) Allan Hardy. All rights reserved. // -using App.Metrics.Formatters; using App.Metrics.Registry; using App.Metrics.Tagging; @@ -16,12 +15,6 @@ public class MetricsOptions { private const string DefaultContext = "Application"; - public MetricsOptions() - { - OutputMetricsFormatters = new MetricsFormatterCollection(); - OutputEnvFormatters = new EnvFormatterCollection(); - } - /// /// Gets or sets a value indicating whether or not to [add default global tags]. e.g. app, server, env /// @@ -39,22 +32,6 @@ public MetricsOptions() /// public string DefaultContextLabel { get; set; } = DefaultContext; - /// - /// Gets or sets the default to use when metrics are attempted to be formatted. - /// - /// - /// The default s that is used by this application. - /// - public IMetricsOutputFormatter DefaultOutputMetricsFormatter { get; set; } - - /// - /// Gets or sets the default to use when the environment's info is attempted to be formatted. - /// - /// - /// The default s that is used by this application. - /// - public IEnvOutputFormatter DefaultOutputEnvFormatter { get; set; } - /// /// Gets or sets the global tags to apply on all metrics when reporting. /// @@ -72,23 +49,6 @@ public MetricsOptions() /// true if [metrics enabled]; otherwise, false. /// public bool MetricsEnabled { get; set; } = true; - - /// - /// Gets a list of s that are used by this application to format metric - /// results. - /// - /// - /// A list of s that are used by this application. - /// - public MetricsFormatterCollection OutputMetricsFormatters { get; } - - /// - /// Gets a list of s that are used by this application to format environment info. - /// - /// - /// A list of s that are used by this application. - /// - public EnvFormatterCollection OutputEnvFormatters { get; } } // ReSharper restore AutoPropertyCanBeMadeGetOnly.Global diff --git a/src/App.Metrics.Core/MetricsRoot.cs b/src/App.Metrics.Core/MetricsRoot.cs new file mode 100644 index 00000000..5693f53d --- /dev/null +++ b/src/App.Metrics.Core/MetricsRoot.cs @@ -0,0 +1,75 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System; +using App.Metrics.Filters; +using App.Metrics.Formatters; +using App.Metrics.Infrastructure; + +namespace App.Metrics +{ + internal class MetricsRoot : IMetricsRoot, IMetrics + { + private readonly EnvironmentInfoProvider _environmentInfoProvider; + private readonly IMetrics _metrics; + + public MetricsRoot( + IMetrics metrics, + MetricsOptions options, + MetricsFormatterCollection metricsOutputFormatters, + EnvFormatterCollection envOutputFormatters, + IMetricsOutputFormatter defaultMetricsOutputFormatter, + IEnvOutputFormatter defaultEnvOutputFormatter, + EnvironmentInfoProvider environmentInfoProvider) + { + Options = options ?? throw new ArgumentNullException(nameof(options)); + _metrics = metrics ?? throw new ArgumentNullException(nameof(metrics)); + _environmentInfoProvider = new EnvironmentInfoProvider(); + OutputMetricsFormatters = metricsOutputFormatters ?? new MetricsFormatterCollection(); + OutputEnvFormatters = envOutputFormatters ?? new EnvFormatterCollection(); + DefaultOutputMetricsFormatter = defaultMetricsOutputFormatter; + DefaultOutputEnvFormatter = defaultEnvOutputFormatter; + _environmentInfoProvider = environmentInfoProvider; + } + + /// + public IBuildMetrics Build => _metrics.Build; + + /// + public IClock Clock => _metrics.Clock; + + /// + public IFilterMetrics Filter => _metrics.Filter; + + /// + public IManageMetrics Manage => _metrics.Manage; + + /// + public IMeasureMetrics Measure => _metrics.Measure; + + /// + public IProvideMetrics Provider => _metrics.Provider; + + /// + public IProvideMetricValues Snapshot => _metrics.Snapshot; + + /// + public MetricsFormatterCollection OutputMetricsFormatters { get; } + + /// + public IMetricsOutputFormatter DefaultOutputMetricsFormatter { get; } + + /// + public IEnvOutputFormatter DefaultOutputEnvFormatter { get; } + + /// + public EnvFormatterCollection OutputEnvFormatters { get; } + + /// + public MetricsOptions Options { get; } + + /// + public EnvironmentInfo EnvironmentInfo => _environmentInfoProvider.Build(); + } +} \ No newline at end of file diff --git a/src/App.Metrics.Core/ReservoirSampling/DefaultSamplingReservoirProvider.cs b/src/App.Metrics.Core/ReservoirSampling/DefaultSamplingReservoirProvider.cs index 5f8a3560..35c59919 100644 --- a/src/App.Metrics.Core/ReservoirSampling/DefaultSamplingReservoirProvider.cs +++ b/src/App.Metrics.Core/ReservoirSampling/DefaultSamplingReservoirProvider.cs @@ -3,14 +3,11 @@ // using System; -using App.Metrics.ReservoirSampling.ExponentialDecay; namespace App.Metrics.ReservoirSampling { public class DefaultSamplingReservoirProvider { - public DefaultSamplingReservoirProvider() { Instance = () => new DefaultForwardDecayingReservoir(); } - public DefaultSamplingReservoirProvider(Func instance) { Instance = instance; } public Func Instance { get; } diff --git a/src/App.Metrics.Core/ReservoirSampling/ExponentialDecay/DefaultForwardDecayingReservoir.cs b/src/App.Metrics.Core/ReservoirSampling/ExponentialDecay/DefaultForwardDecayingReservoir.cs index de6557e5..39fc9734 100644 --- a/src/App.Metrics.Core/ReservoirSampling/ExponentialDecay/DefaultForwardDecayingReservoir.cs +++ b/src/App.Metrics.Core/ReservoirSampling/ExponentialDecay/DefaultForwardDecayingReservoir.cs @@ -84,7 +84,7 @@ public DefaultForwardDecayingReservoir(int sampleSize, double alpha) /// value the more biased the reservoir will be towards newer values. /// /// The clock type to use for calculating processing time. - /// asdfasf + /// The scheduler used to re-scaling // ReSharper disable MemberCanBePrivate.Global public DefaultForwardDecayingReservoir(int sampleSize, double alpha, IClock clock, IScheduler scheduler = null) // ReSharper restore MemberCanBePrivate.Global diff --git a/src/App.Metrics.Formatters.Ascii/App.Metrics.Formatters.Ascii.csproj b/src/App.Metrics.Formatters.Ascii/App.Metrics.Formatters.Ascii.csproj index e88c7821..d2521710 100644 --- a/src/App.Metrics.Formatters.Ascii/App.Metrics.Formatters.Ascii.csproj +++ b/src/App.Metrics.Formatters.Ascii/App.Metrics.Formatters.Ascii.csproj @@ -4,7 +4,7 @@ App Metrics Formatters for metrics and environment data to plain text. - netstandard2.0 + netstandard1.6;net452 true appmetrics;metrics;ascii @@ -13,4 +13,14 @@ + + $(DefineConstants);CLASSIC + + + + + + + + diff --git a/src/App.Metrics.Formatters.Ascii/Builder/EnvTextOutputFormatterBuider.cs b/src/App.Metrics.Formatters.Ascii/Builder/EnvTextOutputFormatterBuider.cs new file mode 100644 index 00000000..f37971b8 --- /dev/null +++ b/src/App.Metrics.Formatters.Ascii/Builder/EnvTextOutputFormatterBuider.cs @@ -0,0 +1,47 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System; +using App.Metrics.Formatters.Ascii; + +// ReSharper disable CheckNamespace +namespace App.Metrics + // ReSharper restore CheckNamespace +{ + /// + /// Builder for configuring environment information plain text output formatting using an + /// . + /// + public static class EnvTextOutputFormatterBuider + { + /// + /// Add the allowing environment information to optionally be reported as plain text. + /// + /// + /// The used to configuring formatting + /// options. + /// + /// The plain text formatting options to use. + /// + /// An that can be used to further configure the App Metrics. + /// + public static IMetricsBuilder AsPlainText( + this EnvOutputFormattingBuilder envFormattingBuilder, + Action setupAction = null) + { + if (envFormattingBuilder == null) + { + throw new ArgumentNullException(nameof(envFormattingBuilder)); + } + + var options = new MetricsTextOptions(); + + setupAction?.Invoke(options); + + var formatter = new EnvInfoTextOutputFormatter(options); + + return envFormattingBuilder.Using(formatter); + } + } +} \ No newline at end of file diff --git a/src/App.Metrics.Formatters.Ascii/Builder/MetricsTextOutputFormatterBuilder.cs b/src/App.Metrics.Formatters.Ascii/Builder/MetricsTextOutputFormatterBuilder.cs new file mode 100644 index 00000000..f740e882 --- /dev/null +++ b/src/App.Metrics.Formatters.Ascii/Builder/MetricsTextOutputFormatterBuilder.cs @@ -0,0 +1,47 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System; +using App.Metrics.Formatters.Ascii; + +// ReSharper disable CheckNamespace +namespace App.Metrics + // ReSharper restore CheckNamespace +{ + /// + /// Builder for configuring metric plain text output formatting using an + /// . + /// + public static class MetricsTextOutputFormatterBuilder + { + /// + /// Add the allowing metrics to optionally be reported as plain text. + /// + /// + /// The used to configuring formatting + /// options. + /// + /// The plain text formatting options to use. + /// + /// An that can be used to further configure the App Metrics. + /// + public static IMetricsBuilder AsPlainText( + this MetricsOutputFormattingBuilder metricFormattingBuilder, + Action setupAction = null) + { + if (metricFormattingBuilder == null) + { + throw new ArgumentNullException(nameof(metricFormattingBuilder)); + } + + var options = new MetricsTextOptions(); + + setupAction?.Invoke(options); + + var formatter = new MetricsTextOutputFormatter(); + + return metricFormattingBuilder.Using(formatter); + } + } +} diff --git a/src/App.Metrics.Formatters.Ascii/DependencyInjection/MetricsTextMetricsBuilderExtensions.cs b/src/App.Metrics.Formatters.Ascii/DependencyInjection/MetricsTextMetricsBuilderExtensions.cs deleted file mode 100644 index 11d92c3b..00000000 --- a/src/App.Metrics.Formatters.Ascii/DependencyInjection/MetricsTextMetricsBuilderExtensions.cs +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -using System; -using App.Metrics.Formatters.Ascii; - -// ReSharper disable CheckNamespace -namespace Microsoft.Extensions.DependencyInjection - // ReSharper restore CheckNamespace -{ - /// - /// Extensions methods for configuring App Metrics via an . - /// - public static class MetricsTextMetricsBuilderExtensions - { - /// - /// Adds configuration of for the application. - /// - /// The . - /// The which need to be configured. - /// A reference to this instance after the operation has completed. - public static IMetricsBuilder AddTextOptions( - this IMetricsBuilder builder, - Action setupAction) - { - if (builder == null) - { - throw new ArgumentNullException(nameof(builder)); - } - - if (setupAction == null) - { - throw new ArgumentNullException(nameof(setupAction)); - } - - builder.Services.Configure(setupAction); - - return builder; - } - } -} \ No newline at end of file diff --git a/src/App.Metrics.Formatters.Ascii/DependencyInjection/MetricsTextMetricsCoreBuilderExtensions.cs b/src/App.Metrics.Formatters.Ascii/DependencyInjection/MetricsTextMetricsCoreBuilderExtensions.cs deleted file mode 100644 index b0ac908c..00000000 --- a/src/App.Metrics.Formatters.Ascii/DependencyInjection/MetricsTextMetricsCoreBuilderExtensions.cs +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -using System; -using App.Metrics; -using App.Metrics.Formatters; -using App.Metrics.Formatters.Ascii.Internal; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Options; - -// ReSharper disable CheckNamespace -namespace Microsoft.Extensions.DependencyInjection - // ReSharper restore CheckNamespace -{ - /// - /// Extensions methods for configuring App Metrics via an . - /// - public static class MetricsTextMetricsCoreBuilderExtensions - { - /// - /// Adds the default Text and to - /// . - /// - /// The . - /// A reference to this instance after the operation has completed. - public static IMetricsCoreBuilder AddTextFormatters(this IMetricsCoreBuilder builder) - { - if (builder == null) - { - throw new ArgumentNullException(nameof(builder)); - } - - AddTextFormatterServices(builder.Services); - - return builder; - } - - internal static void AddTextFormatterServices(IServiceCollection services) - { - services.TryAddEnumerable( - ServiceDescriptor.Transient, MetricsTextOptionsSetup>()); - } - } -} diff --git a/src/App.Metrics.Formatters.Ascii/EnvironmentInfoTextOutputFormatter.cs b/src/App.Metrics.Formatters.Ascii/EnvInfoTextOutputFormatter.cs similarity index 73% rename from src/App.Metrics.Formatters.Ascii/EnvironmentInfoTextOutputFormatter.cs rename to src/App.Metrics.Formatters.Ascii/EnvInfoTextOutputFormatter.cs index ad56d138..8f981bf6 100644 --- a/src/App.Metrics.Formatters.Ascii/EnvironmentInfoTextOutputFormatter.cs +++ b/src/App.Metrics.Formatters.Ascii/EnvInfoTextOutputFormatter.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) Allan Hardy. All rights reserved. // @@ -7,20 +7,23 @@ using System.Threading; using System.Threading.Tasks; using App.Metrics.Infrastructure; +#if !NETSTANDARD1_3 +using App.Metrics.Internal; +#endif using App.Metrics.Serialization; namespace App.Metrics.Formatters.Ascii { - public class EnvironmentInfoTextOutputFormatter : IEnvOutputFormatter + public class EnvInfoTextOutputFormatter : IEnvOutputFormatter { private readonly MetricsTextOptions _options; - public EnvironmentInfoTextOutputFormatter() + public EnvInfoTextOutputFormatter() { _options = new MetricsTextOptions(); } - public EnvironmentInfoTextOutputFormatter(MetricsTextOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); } + public EnvInfoTextOutputFormatter(MetricsTextOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); } /// public MetricsMediaTypeValue MediaType => new MetricsMediaTypeValue("text", "vnd.appmetrics.env", "v1", "plain"); @@ -46,7 +49,11 @@ public EnvironmentInfoTextOutputFormatter() } } +#if NETSTANDARD1_3 return Task.CompletedTask; +#else + return AppMetricsTaskHelper.CompletedTask(); +#endif } } } diff --git a/src/App.Metrics.Formatters.Ascii/EnvInfoTextWriter.cs b/src/App.Metrics.Formatters.Ascii/EnvInfoTextWriter.cs index 639d8975..19170427 100644 --- a/src/App.Metrics.Formatters.Ascii/EnvInfoTextWriter.cs +++ b/src/App.Metrics.Formatters.Ascii/EnvInfoTextWriter.cs @@ -42,8 +42,6 @@ public void Write(EnvironmentInfo envInfo) _textWriter.Write('\n'); _textWriter.Write(PaddedFormat("Framework Description", envInfo.FrameworkDescription)); _textWriter.Write('\n'); - _textWriter.Write(PaddedFormat("Host Name", envInfo.HostName)); - _textWriter.Write('\n'); _textWriter.Write(PaddedFormat("Local Time", envInfo.LocalTimeString)); _textWriter.Write('\n'); _textWriter.Write(PaddedFormat("Machine Name", envInfo.MachineName)); @@ -56,8 +54,6 @@ public void Write(EnvironmentInfo envInfo) _textWriter.Write('\n'); _textWriter.Write(PaddedFormat("Process Architecture", envInfo.ProcessArchitecture)); _textWriter.Write('\n'); - _textWriter.Write(PaddedFormat("Process Name", envInfo.ProcessName)); - _textWriter.Write('\n'); } /// @@ -71,7 +67,6 @@ protected virtual void Dispose(bool disposing) { if (disposing) { - _textWriter?.Close(); _textWriter?.Dispose(); } } diff --git a/src/App.Metrics.Formatters.Ascii/Internal/MetricsTextOptionsSetup.cs b/src/App.Metrics.Formatters.Ascii/Internal/MetricsTextOptionsSetup.cs deleted file mode 100644 index 38b46d86..00000000 --- a/src/App.Metrics.Formatters.Ascii/Internal/MetricsTextOptionsSetup.cs +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -using System; -using Microsoft.Extensions.Options; - -namespace App.Metrics.Formatters.Ascii.Internal -{ - /// - /// Sets up default ASCII formatting options for . - /// - public class MetricsTextOptionsSetup : IConfigureOptions - { - private readonly MetricsTextOptions _textOptions; - - public MetricsTextOptionsSetup(IOptions asciiOptionsAccessor) - { - _textOptions = asciiOptionsAccessor.Value ?? throw new ArgumentNullException(nameof(asciiOptionsAccessor)); - } - - public void Configure(MetricsOptions options) - { - var formatter = new MetricsTextOutputFormatter(_textOptions); - var envFormatter = new EnvironmentInfoTextOutputFormatter(_textOptions); - - options.OutputMetricsFormatters.Add(formatter); - options.OutputEnvFormatters.Add(envFormatter); - } - } -} \ No newline at end of file diff --git a/src/App.Metrics.Formatters.Ascii/MetricSnapshotTextWriter.cs b/src/App.Metrics.Formatters.Ascii/MetricSnapshotTextWriter.cs index 60d92511..0f7cdeee 100644 --- a/src/App.Metrics.Formatters.Ascii/MetricSnapshotTextWriter.cs +++ b/src/App.Metrics.Formatters.Ascii/MetricSnapshotTextWriter.cs @@ -92,7 +92,6 @@ protected virtual void Dispose(bool disposing) if (disposing) { _textPoints.Write(_textWriter, _separator, _padding); - _textWriter?.Close(); _textWriter?.Dispose(); } } diff --git a/src/App.Metrics.Formatters.Ascii/MetricsTextOutputFormatter.cs b/src/App.Metrics.Formatters.Ascii/MetricsTextOutputFormatter.cs index f0f0137a..de48081f 100644 --- a/src/App.Metrics.Formatters.Ascii/MetricsTextOutputFormatter.cs +++ b/src/App.Metrics.Formatters.Ascii/MetricsTextOutputFormatter.cs @@ -6,6 +6,9 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +#if !NETSTANDARD1_3 +using App.Metrics.Internal; +#endif using App.Metrics.Serialization; namespace App.Metrics.Formatters.Ascii @@ -50,7 +53,11 @@ public MetricsTextOutputFormatter() } } +#if NETSTANDARD1_3 return Task.CompletedTask; +#else + return AppMetricsTaskHelper.CompletedTask(); +#endif } } } \ No newline at end of file diff --git a/src/App.Metrics.Formatters.Json/App.Metrics.Formatters.Json.csproj b/src/App.Metrics.Formatters.Json/App.Metrics.Formatters.Json.csproj index c8e7783a..cf326f69 100644 --- a/src/App.Metrics.Formatters.Json/App.Metrics.Formatters.Json.csproj +++ b/src/App.Metrics.Formatters.Json/App.Metrics.Formatters.Json.csproj @@ -4,7 +4,7 @@ App Metrics Formatters for metrics and environment data to JSON using Newtonsoft.Json. - netstandard2.0 + netstandard1.6;net452 true appmetrics;metrics;json @@ -17,4 +17,14 @@ + + $(DefineConstants);CLASSIC + + + + + + + + diff --git a/src/App.Metrics.Formatters.Json/Builder/EnvJsonOutputFormatterBuilder.cs b/src/App.Metrics.Formatters.Json/Builder/EnvJsonOutputFormatterBuilder.cs new file mode 100644 index 00000000..f7ae8741 --- /dev/null +++ b/src/App.Metrics.Formatters.Json/Builder/EnvJsonOutputFormatterBuilder.cs @@ -0,0 +1,47 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System; +using App.Metrics.Formatters.Json; + +// ReSharper disable CheckNamespace +namespace App.Metrics + // ReSharper restore CheckNamespace +{ + /// + /// Builder for configuring environment information JSON output formatting using an + /// . + /// + public static class EnvJsonOutputFormatterBuilder + { + /// + /// Add the allowing metric values to optionally be reported as JSON. + /// + /// + /// The used to configuring formatting + /// options. + /// + /// The JSON formatting options to use. + /// + /// An that can be used to further configure the App Metrics. + /// + public static IMetricsBuilder AsJson( + this EnvOutputFormattingBuilder envFormattingBuilder, + Action setupAction = null) + { + if (envFormattingBuilder == null) + { + throw new ArgumentNullException(nameof(envFormattingBuilder)); + } + + var options = new MetricsJsonOptions(); + + setupAction?.Invoke(options); + + var formatter = new EnvInfoJsonOutputFormatter(options.SerializerSettings); + + return envFormattingBuilder.Using(formatter); + } + } +} diff --git a/src/App.Metrics.Formatters.Json/Builder/MetricsJsonOutputFormatterBuilder.cs b/src/App.Metrics.Formatters.Json/Builder/MetricsJsonOutputFormatterBuilder.cs new file mode 100644 index 00000000..194cc4bb --- /dev/null +++ b/src/App.Metrics.Formatters.Json/Builder/MetricsJsonOutputFormatterBuilder.cs @@ -0,0 +1,47 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System; +using App.Metrics.Formatters.Json; + +// ReSharper disable CheckNamespace +namespace App.Metrics + // ReSharper restore CheckNamespace +{ + /// + /// Builder for configuring metric JSON output formatting using an + /// . + /// + public static class MetricsJsonOutputFormatterBuilder + { + /// + /// Add the allowing metrics to optionally be reported as JSON. + /// + /// + /// The used to configuring formatting + /// options. + /// + /// The JSON formatting options to use. + /// + /// An that can be used to further configure the App Metrics. + /// + public static IMetricsBuilder AsJson( + this MetricsOutputFormattingBuilder metricFormattingBuilder, + Action setupAction = null) + { + if (metricFormattingBuilder == null) + { + throw new ArgumentNullException(nameof(metricFormattingBuilder)); + } + + var options = new MetricsJsonOptions(); + + setupAction?.Invoke(options); + + var formatter = new MetricsJsonOutputFormatter(options.SerializerSettings); + + return metricFormattingBuilder.Using(formatter); + } + } +} diff --git a/src/App.Metrics.Formatters.Json/DependencyInjection/MetricsJsonMetricsBuilderExtensions.cs b/src/App.Metrics.Formatters.Json/DependencyInjection/MetricsJsonMetricsBuilderExtensions.cs deleted file mode 100644 index 105f9e5c..00000000 --- a/src/App.Metrics.Formatters.Json/DependencyInjection/MetricsJsonMetricsBuilderExtensions.cs +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -using System; -using App.Metrics.Formatters.Json; - -// ReSharper disable CheckNamespace -namespace Microsoft.Extensions.DependencyInjection - // ReSharper restore CheckNamespace -{ - /// - /// Extensions methods for configuring App Metrics via an . - /// - public static class MetricsJsonMetricsBuilderExtensions - { - /// - /// Adds configuration of for the application. - /// - /// The . - /// The which need to be configured. - /// A reference to this instance after the operation has completed. - public static IMetricsBuilder AddJsonOptions( - this IMetricsBuilder builder, - Action setupAction) - { - if (builder == null) - { - throw new ArgumentNullException(nameof(builder)); - } - - if (setupAction == null) - { - throw new ArgumentNullException(nameof(setupAction)); - } - - builder.Services.Configure(setupAction); - - return builder; - } - } -} \ No newline at end of file diff --git a/src/App.Metrics.Formatters.Json/DependencyInjection/MetricsJsonMetricsCoreBuilderExtensions.cs b/src/App.Metrics.Formatters.Json/DependencyInjection/MetricsJsonMetricsCoreBuilderExtensions.cs deleted file mode 100644 index 9f2e8400..00000000 --- a/src/App.Metrics.Formatters.Json/DependencyInjection/MetricsJsonMetricsCoreBuilderExtensions.cs +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -using System; -using App.Metrics; -using App.Metrics.Formatters; -using App.Metrics.Formatters.Json.Internal; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Options; - -// ReSharper disable CheckNamespace -namespace Microsoft.Extensions.DependencyInjection - // ReSharper restore CheckNamespace -{ - /// - /// Extensions methods for configuring App Metrics via an . - /// - public static class MetricsJsonMetricsCoreBuilderExtensions - { - /// - /// Adds the default JSON and to - /// . - /// - /// The . - /// A reference to this instance after the operation has completed. - public static IMetricsCoreBuilder AddJsonFormatters(this IMetricsCoreBuilder builder) - { - if (builder == null) - { - throw new ArgumentNullException(nameof(builder)); - } - - AddJsonFormatterServices(builder.Services); - - return builder; - } - - internal static void AddJsonFormatterServices(IServiceCollection services) - { - var jsonOptionsSetupServiceDescriptor = ServiceDescriptor.Transient, MetricsJsonOptionsSetup>(); - services.TryAddEnumerable(jsonOptionsSetupServiceDescriptor); - } - } -} \ No newline at end of file diff --git a/src/App.Metrics.Formatters.Json/EnvInfoJsonOutputFormatter.cs b/src/App.Metrics.Formatters.Json/EnvInfoJsonOutputFormatter.cs index 46005f5a..81cb6420 100644 --- a/src/App.Metrics.Formatters.Json/EnvInfoJsonOutputFormatter.cs +++ b/src/App.Metrics.Formatters.Json/EnvInfoJsonOutputFormatter.cs @@ -7,6 +7,9 @@ using System.Threading; using System.Threading.Tasks; using App.Metrics.Infrastructure; +#if !NETSTANDARD1_3 +using App.Metrics.Internal; +#endif using Newtonsoft.Json; namespace App.Metrics.Formatters.Json @@ -45,8 +48,11 @@ public EnvInfoJsonOutputFormatter(JsonSerializerSettings serializerSettings) serilizer.Serialize(jw, environmentInfo); } } - +#if NETSTANDARD1_3 return Task.CompletedTask; +#else + return AppMetricsTaskHelper.CompletedTask(); +#endif } } } diff --git a/src/App.Metrics.Formatters.Json/Internal/MetricsJsonOptionsSetup.cs b/src/App.Metrics.Formatters.Json/Internal/MetricsJsonOptionsSetup.cs deleted file mode 100644 index c7d103f5..00000000 --- a/src/App.Metrics.Formatters.Json/Internal/MetricsJsonOptionsSetup.cs +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -using System; -using Microsoft.Extensions.Options; - -namespace App.Metrics.Formatters.Json.Internal -{ - /// - /// Sets up default JSON formatting options for . - /// - public class MetricsJsonOptionsSetup : IConfigureOptions - { - private readonly MetricsJsonOptions _jsonOptions; - - public MetricsJsonOptionsSetup(IOptions asciiOptionsAccessor) - { - _jsonOptions = asciiOptionsAccessor.Value ?? throw new ArgumentNullException(nameof(asciiOptionsAccessor)); - } - - /// - public void Configure(MetricsOptions options) - { - var formatter = new MetricsJsonOutputFormatter(_jsonOptions.SerializerSettings); - var envFormatter = new EnvInfoJsonOutputFormatter(_jsonOptions.SerializerSettings); - - options.OutputMetricsFormatters.Add(formatter); - options.OutputEnvFormatters.Add(envFormatter); - } - } -} \ No newline at end of file diff --git a/src/App.Metrics.Formatters.Json/MetricsJsonOutputFormatter.cs b/src/App.Metrics.Formatters.Json/MetricsJsonOutputFormatter.cs index 3926bb8e..49830886 100644 --- a/src/App.Metrics.Formatters.Json/MetricsJsonOutputFormatter.cs +++ b/src/App.Metrics.Formatters.Json/MetricsJsonOutputFormatter.cs @@ -6,6 +6,9 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +#if !NETSTANDARD1_3 +using App.Metrics.Internal; +#endif using Newtonsoft.Json; namespace App.Metrics.Formatters.Json @@ -45,7 +48,11 @@ public MetricsJsonOutputFormatter(JsonSerializerSettings serializerSettings) } } +#if NETSTANDARD1_3 return Task.CompletedTask; +#else + return AppMetricsTaskHelper.CompletedTask(); +#endif } } } \ No newline at end of file diff --git a/src/App.Metrics/App.Metrics.csproj b/src/App.Metrics/App.Metrics.csproj index a1207765..4841d3ef 100644 --- a/src/App.Metrics/App.Metrics.csproj +++ b/src/App.Metrics/App.Metrics.csproj @@ -9,6 +9,10 @@ appmetrics;metrics;apdex;meter;gauge;counter;timer;histogram + + + + diff --git a/src/App.Metrics/AppMetrics.cs b/src/App.Metrics/AppMetrics.cs new file mode 100644 index 00000000..ca6b63c8 --- /dev/null +++ b/src/App.Metrics/AppMetrics.cs @@ -0,0 +1,37 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using App.Metrics.ReservoirSampling.ExponentialDecay; + +namespace App.Metrics +{ + /// + /// Provides convenience methods for creating instances of and with pre-configured defaults. + /// + public static class AppMetrics + { + /// + /// Initializes a new instance of the class with pre-configured defaults. + /// + /// + /// The following defaults are applied to the returned : + /// use for sampling, JSON and Plain Text metric and environment + /// information formatters are added, the default metrics formatting is set to JSON, the default environment + /// information formatting is set to Plain Text, the default metrics formatting is set to JSON. + /// + /// The initialized . + public static IMetricsBuilder CreateDefaultBuilder() + { + var builder = new MetricsBuilder() + .OutputEnvInfo.AsPlainText() + .OutputEnvInfo.AsJson() + .OutputMetrics.AsJson() + .OutputMetrics.AsPlainText() + .SampleWith.ForwardDecaying() + .TimeWith.StopwatchClock(); + + return builder; + } + } +} \ No newline at end of file diff --git a/src/App.Metrics/MetricsServiceCollectionExtensions.cs b/src/App.Metrics/MetricsServiceCollectionExtensions.cs deleted file mode 100644 index cad1a661..00000000 --- a/src/App.Metrics/MetricsServiceCollectionExtensions.cs +++ /dev/null @@ -1,163 +0,0 @@ -// -// Copyright (c) Allan Hardy. All rights reserved. -// - -using System; -using App.Metrics; -using App.Metrics.Filtering; -using App.Metrics.Formatters.Ascii; -using App.Metrics.Formatters.Json; -using App.Metrics.Infrastructure; -using App.Metrics.Internal; -using App.Metrics.ReservoirSampling.ExponentialDecay; -using Microsoft.Extensions.Configuration; - -// ReSharper disable CheckNamespace -namespace Microsoft.Extensions.DependencyInjection - // ReSharper restore CheckNamespace -{ - /// - /// Extension methods for setting up App Metrics services in an . - /// - public static class MetricsServiceCollectionExtensions - { - /// - /// Adds the metrics services and configuration to the . - /// - /// The to add services to. - /// - /// An that can be used to further configure the App Metrics services. - /// - public static IMetricsBuilder AddMetrics(this IServiceCollection services) - { - var builder = services.AddMetricsCore(); - - // - // Add infrastructure defaults - // - builder.AddClockType(); - - // - // Add filtering defaults - // - builder.AddGlobalFilter(new NoOpMetricsFilter()); - - // - // Add sampling defaults - // - builder.AddDefaultReservoir(() => new DefaultForwardDecayingReservoir()); - - // - // Add default formatters - // - builder.AddJsonFormatters(); - builder.AddTextFormatters(); - services.Configure(AddDefaultFormatterOptions); - - return new MetricsBuilder(services); - } - - /// - /// Adds the metrics services and configuration to the . - /// - /// The to add services to. - /// - /// The from where to load . - /// - /// - /// An that can be used to further configure the App Metrics services. - /// - public static IMetricsBuilder AddMetrics(this IServiceCollection services, IConfiguration configuration) - { - var builder = services.AddMetrics(); - - services.Configure(configuration); - - return builder; - } - - /// - /// Adds the metrics services and configuration to the . - /// - /// The to add services to. - /// - /// An to configure the provided . - /// - /// - /// The from where to load . - /// - /// - /// An that can be used to further configure the App Metrics services. - /// - public static IMetricsBuilder AddMetrics( - this IServiceCollection services, - Action setupAction, - IConfiguration configuration) - { - var builder = services.AddMetrics(); - - services.Configure(setupAction); - services.Configure(configuration); - - return builder; - } - - /// - /// Adds the metrics services and configuration to the . - /// - /// The to add services to. - /// - /// The from where to load . - /// - /// - /// An to configure the provided . - /// - /// - /// An that can be used to further configure the App Metrics services. - /// - public static IMetricsBuilder AddMetrics( - this IServiceCollection services, - IConfiguration configuration, - Action setupAction) - { - var builder = services.AddMetrics(); - - services.Configure(configuration); - services.Configure(setupAction); - - return builder; - } - - /// - /// Adds the metrics services and configuration to the . - /// - /// The to add services to. - /// - /// An to configure the provided . - /// - /// - /// An that can be used to further configure the App Metrics services. - /// - public static IMetricsBuilder AddMetrics(this IServiceCollection services, Action setupAction) - { - var builder = services.AddMetrics(); - - services.Configure(setupAction); - - return builder; - } - - private static void AddDefaultFormatterOptions(MetricsOptions options) - { - if (options.DefaultOutputMetricsFormatter == null) - { - options.DefaultOutputMetricsFormatter = options.OutputMetricsFormatters.GetType(); - } - - if (options.DefaultOutputEnvFormatter == null) - { - options.DefaultOutputEnvFormatter = options.OutputEnvFormatters.GetType(); - } - } - } -} \ No newline at end of file diff --git a/test/App.Metrics.Facts/App.Metrics.Facts.csproj b/test/App.Metrics.Facts/App.Metrics.Facts.csproj index 91da5d96..c89091c5 100644 --- a/test/App.Metrics.Facts/App.Metrics.Facts.csproj +++ b/test/App.Metrics.Facts/App.Metrics.Facts.csproj @@ -18,8 +18,6 @@ - - diff --git a/test/App.Metrics.Facts/Builder/EnvOutputFormattingBuilderTests.cs b/test/App.Metrics.Facts/Builder/EnvOutputFormattingBuilderTests.cs new file mode 100644 index 00000000..fbc2bf26 --- /dev/null +++ b/test/App.Metrics.Facts/Builder/EnvOutputFormattingBuilderTests.cs @@ -0,0 +1,89 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System; +using App.Metrics.Formatters.Ascii; +using App.Metrics.Formatters.Json; +using FluentAssertions; +using Xunit; + +namespace App.Metrics.Facts.Builder +{ + public class EnvOutputFormattingBuilderTests + { + [Fact] + public void Cannot_set_null_env_output_formatter() + { + // Arrange + Action action = () => + { + // Act + var builder = new MetricsBuilder().OutputEnvInfo.Using(null); + }; + + // Assert + action.ShouldThrow(); + } + + [Fact] + public void Default_env_output_formatter_should_be_first_formatter_selected_via_instantiation() + { + // Arrange + var builder = new MetricsBuilder() + .OutputEnvInfo.Using(new EnvInfoTextOutputFormatter()) + .OutputEnvInfo.Using(new EnvInfoJsonOutputFormatter()); + + // Act + var metrics = builder.Build(); + + // Assert + metrics.DefaultOutputEnvFormatter.Should().BeOfType(); + } + + [Fact] + public void Default_env_output_formatter_should_be_first_formatter_selected_via_type() + { + // Arrange + var builder = new MetricsBuilder() + .OutputEnvInfo.Using() + .OutputEnvInfo.Using(); + + // Act + var metrics = builder.Build(); + + // Assert + metrics.DefaultOutputEnvFormatter.Should().BeOfType(); + } + + [Fact] + public void Should_set_env_output_formatters_when_selected_via_instantiation() + { + // Arrange + var builder = new MetricsBuilder() + .OutputEnvInfo.Using(new EnvInfoTextOutputFormatter()) + .OutputEnvInfo.Using(new EnvInfoJsonOutputFormatter()); + + // Act + var metrics = builder.Build(); + + // Assert + metrics.OutputEnvFormatters.Count.Should().Be(2); + } + + [Fact] + public void Should_set_env_output_formatters_when_selected_via_type() + { + // Arrange + var builder = new MetricsBuilder() + .OutputEnvInfo.Using() + .OutputEnvInfo.Using(); + + // Act + var metrics = builder.Build(); + + // Assert + metrics.OutputEnvFormatters.Count.Should().Be(2); + } + } +} \ No newline at end of file diff --git a/test/App.Metrics.Facts/Builder/MetricsClockBuilderTests.cs b/test/App.Metrics.Facts/Builder/MetricsClockBuilderTests.cs new file mode 100644 index 00000000..92e90673 --- /dev/null +++ b/test/App.Metrics.Facts/Builder/MetricsClockBuilderTests.cs @@ -0,0 +1,82 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System; +using App.Metrics.FactsCommon; +using App.Metrics.Infrastructure; +using FluentAssertions; +using Xunit; + +namespace App.Metrics.Facts.Builder +{ + public class MetricsClockBuilderTests + { + [Fact] + public void Can_set_clock__to_stopwatch_clock_should_the_last_selected_clock() + { + // Arrange + var builder = new MetricsBuilder().TimeWith.Clock(); + + // Act + builder.TimeWith.StopwatchClock(); + var metrics = builder.Build(); + + // Assert + metrics.Clock.Should().BeOfType(); + } + + [Fact] + public void Can_set_clock_to_custom_implementation() + { + // Arrange + var builder = new MetricsBuilder().TimeWith.Clock(); + + // Act + var metrics = builder.Build(); + + // Assert + metrics.Clock.Should().BeOfType(); + } + + [Fact] + public void Can_set_clock_to_system_clock() + { + // Arrange + var builder = new MetricsBuilder().TimeWith.SystemClock(); + + // Act + var metrics = builder.Build(); + + // Assert + metrics.Clock.Should().BeOfType(); + } + + [Fact] + public void Can_set_clock_using_instantiation() + { + // Arrange + var builder = new MetricsBuilder().TimeWith.Clock(new TestClock()); + + // Act + var metrics = builder.Build(); + + // Assert + metrics.Clock.Should().BeOfType(); + } + + [Fact] + public void Cannot_set_null_clock() + { + // Arrange + Action action = () => + { + // Act + var builder = new MetricsBuilder().TimeWith.Clock(null); + }; + + // Assert + action.ShouldThrow(); + } + } +} \ No newline at end of file diff --git a/test/App.Metrics.Facts/Builder/MetricsFilterBuilderTests.cs b/test/App.Metrics.Facts/Builder/MetricsFilterBuilderTests.cs new file mode 100644 index 00000000..c81147f8 --- /dev/null +++ b/test/App.Metrics.Facts/Builder/MetricsFilterBuilderTests.cs @@ -0,0 +1,27 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System; +using FluentAssertions; +using Xunit; + +namespace App.Metrics.Facts.Builder +{ + public class MetricsFilterBuilderTests + { + [Fact] + public void Cannot_set_null_filter() + { + // Arrange + Action action = () => + { + // Act + var builder = new MetricsBuilder().Filter.With(filter: null); + }; + + // Assert + action.ShouldThrow(); + } + } +} \ No newline at end of file diff --git a/test/App.Metrics.Facts/Builder/MetricsOptionsBuilderTests.cs b/test/App.Metrics.Facts/Builder/MetricsOptionsBuilderTests.cs new file mode 100644 index 00000000..39746f11 --- /dev/null +++ b/test/App.Metrics.Facts/Builder/MetricsOptionsBuilderTests.cs @@ -0,0 +1,146 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System.Collections.Generic; +using System.Linq; +using App.Metrics.Tagging; +using FluentAssertions; +using Xunit; + +namespace App.Metrics.Facts.Builder +{ + public class MetricsOptionsBuilderTests + { + [Fact] + public void Can_override_option_instance_values_with_key_value_pair_options() + { + // Arrange + var options = new MetricsOptions + { + AddDefaultGlobalTags = true, + MetricsEnabled = true, + DefaultContextLabel = "initial value", + GlobalTags = new GlobalMetricTags(new Dictionary { { "initial", "value" } }) + }; + + var keyValuePairs = new Dictionary + { + { "AddDefaultGlobalTags", "false" }, + { "DefaultContextLabel", "Testing" }, + { "GlobalTags", "tag1=value1,tag2=value2" }, + { "MetricsEnabled", "false" } + }; + + // Act + var metrics = new MetricsBuilder().Options.Configure(options, keyValuePairs).Build(); + + // Assert + metrics.Options.AddDefaultGlobalTags.Should().BeFalse(); + 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.MetricsEnabled.Should().BeFalse(); + } + + [Fact] + public void Can_set_options_via_key_value_pairs() + { + // Arrange + var keyValuePairs = new Dictionary + { + { "AddDefaultGlobalTags", "false" }, + { "DefaultContextLabel", "Testing" }, + { "GlobalTags", "tag1=value1,tag2=value2" }, + { "MetricsEnabled", "false" } + }; + + // Act + var metrics = new MetricsBuilder().Options.Configure(keyValuePairs).Build(); + + // Assert + metrics.Options.AddDefaultGlobalTags.Should().BeFalse(); + 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.MetricsEnabled.Should().BeFalse(); + } + + [Fact] + public void Can_set_options_via_setup_action() + { + // Arrange + void SetupAction(MetricsOptions options) + { + options.MetricsEnabled = false; + options.GlobalTags.Add("tag1", "value1"); + options.AddDefaultGlobalTags = false; + options.DefaultContextLabel = "test"; + } + + // Act + var metrics = new MetricsBuilder().Options.Configure(SetupAction).Build(); + + // Assert + metrics.Options.AddDefaultGlobalTags.Should().BeFalse(); + metrics.Options.DefaultContextLabel.Should().Be("test"); + metrics.Options.GlobalTags.Count.Should().Be(1); + metrics.Options.GlobalTags.First().Key.Should().Be("tag1"); + metrics.Options.GlobalTags.First().Value.Should().Be("value1"); + metrics.Options.MetricsEnabled.Should().BeFalse(); + } + + [Fact] + public void Can_set_options_with_instance() + { + // Arrange + var options = new MetricsOptions(); + options.MetricsEnabled = true; + options.GlobalTags.Add("tag1", "value1"); + options.AddDefaultGlobalTags = false; + options.DefaultContextLabel = "test"; + + // Act + var metrics = new MetricsBuilder().Options.Configure(options).Build(); + + // Assert + metrics.Options.AddDefaultGlobalTags.Should().BeFalse(); + metrics.Options.DefaultContextLabel.Should().Be("test"); + metrics.Options.GlobalTags.Count.Should().Be(1); + metrics.Options.GlobalTags.First().Key.Should().Be("tag1"); + metrics.Options.GlobalTags.First().Value.Should().Be("value1"); + metrics.Options.MetricsEnabled.Should().BeTrue(); + } + + [Fact] + public void Should_add_env_tags_when_required() + { + // Arrange + void SetupAction(MetricsOptions options) + { + options.AddDefaultGlobalTags = true; + options.GlobalTags.Add("tag1", "value1"); + } + + // Act + var metrics = new MetricsBuilder().Options.Configure(SetupAction).Build(); + + // Assert + metrics.Options.GlobalTags.Count.Should().Be(4); + 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("app"); + metrics.Options.GlobalTags.Skip(1).First().Value.Should().Be("testhost"); + metrics.Options.GlobalTags.Skip(2).First().Key.Should().Be("server"); + metrics.Options.GlobalTags.Skip(2).First().Value.Should().NotBeNullOrWhiteSpace(); + metrics.Options.GlobalTags.Skip(3).First().Key.Should().Be("env"); + metrics.Options.GlobalTags.Skip(3).First().Value.Should().Be("debug"); + } + } +} \ No newline at end of file diff --git a/test/App.Metrics.Facts/Builder/MetricsOutputFormattingBuilderTests.cs b/test/App.Metrics.Facts/Builder/MetricsOutputFormattingBuilderTests.cs new file mode 100644 index 00000000..dc4dfb6d --- /dev/null +++ b/test/App.Metrics.Facts/Builder/MetricsOutputFormattingBuilderTests.cs @@ -0,0 +1,89 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System; +using App.Metrics.Formatters.Ascii; +using App.Metrics.Formatters.Json; +using FluentAssertions; +using Xunit; + +namespace App.Metrics.Facts.Builder +{ + public class MetricsOutputFormattingBuilderTests + { + [Fact] + public void Cannot_set_null_metrics_output_formatter() + { + // Arrange + Action action = () => + { + // Act + var builder = new MetricsBuilder().OutputMetrics.Using(null); + }; + + // Assert + action.ShouldThrow(); + } + + [Fact] + public void Default_metrics_output_formatter_should_be_first_formatter_selected_via_instantiation() + { + // Arrange + var builder = new MetricsBuilder() + .OutputMetrics.Using(new MetricsTextOutputFormatter()) + .OutputMetrics.Using(new MetricsJsonOutputFormatter()); + + // Act + var metrics = builder.Build(); + + // Assert + metrics.DefaultOutputMetricsFormatter.Should().BeOfType(); + } + + [Fact] + public void Default_metrics_output_formatter_should_be_first_formatter_selected_via_type() + { + // Arrange + var builder = new MetricsBuilder() + .OutputMetrics.Using() + .OutputMetrics.Using(); + + // Act + var metrics = builder.Build(); + + // Assert + metrics.DefaultOutputMetricsFormatter.Should().BeOfType(); + } + + [Fact] + public void Should_set_metrics_output_formatters_when_selected_via_instantiation() + { + // Arrange + var builder = new MetricsBuilder() + .OutputMetrics.Using(new MetricsTextOutputFormatter()) + .OutputMetrics.Using(new MetricsJsonOutputFormatter()); + + // Act + var metrics = builder.Build(); + + // Assert + metrics.OutputMetricsFormatters.Count.Should().Be(2); + } + + [Fact] + public void Should_set_metrics_output_formatters_when_selected_via_type() + { + // Arrange + var builder = new MetricsBuilder() + .OutputMetrics.Using() + .OutputMetrics.Using(); + + // Act + var metrics = builder.Build(); + + // Assert + metrics.OutputMetricsFormatters.Count.Should().Be(2); + } + } +} \ No newline at end of file diff --git a/test/App.Metrics.Facts/Builder/MetricsReservoirSamplingBuilderTests.cs b/test/App.Metrics.Facts/Builder/MetricsReservoirSamplingBuilderTests.cs new file mode 100644 index 00000000..d5f0db0a --- /dev/null +++ b/test/App.Metrics.Facts/Builder/MetricsReservoirSamplingBuilderTests.cs @@ -0,0 +1,107 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using App.Metrics.Facts.TestHelpers; +using App.Metrics.Internal; +using App.Metrics.ReservoirSampling.ExponentialDecay; +using App.Metrics.ReservoirSampling.SlidingWindow; +using App.Metrics.ReservoirSampling.Uniform; +using FluentAssertions; +using Xunit; + +namespace App.Metrics.Facts.Builder +{ + public class MetricsReservoirSamplingBuilderTests + { + [Fact] + public void Can_set_default_reservoir_to_algorithmr() + { + // Arrange + DefaultMetricsBuilderFactory metricsBuilder; + + // Act + var metrics = new MetricsBuilder().SampleWith.AlgorithmR().Build(); + metricsBuilder = metrics.Build as DefaultMetricsBuilderFactory; + var reservoir = metricsBuilder?.DefaultSamplingReservoir.Instance(); + + // Assert + reservoir.Should().BeOfType(); + } + + [Fact] + public void Can_set_default_reservoir_to_custom_func_reservoir() + { + // Arrange + DefaultMetricsBuilderFactory metricsBuilder; + + // Act + var metrics = new MetricsBuilder().SampleWith.Reservoir(() => new CustomReservoir()).Build(); + metricsBuilder = metrics.Build as DefaultMetricsBuilderFactory; + var reservoir = metricsBuilder?.DefaultSamplingReservoir.Instance(); + + // Assert + reservoir.Should().BeOfType(); + } + + [Fact] + public void Can_set_default_reservoir_to_custom_implementation() + { + // Arrange + DefaultMetricsBuilderFactory metricsBuilder; + + // Act + var metrics = new MetricsBuilder().SampleWith.Reservoir().Build(); + metricsBuilder = metrics.Build as DefaultMetricsBuilderFactory; + var reservoir = metricsBuilder?.DefaultSamplingReservoir.Instance(); + + // Assert + reservoir.Should().BeOfType(); + } + + [Fact] + public void Can_set_default_reservoir_to_forward_decaying_should_the_last_selected_reservoir() + { + // Arrange + DefaultMetricsBuilderFactory metricsBuilder; + + // Act + var metrics = new MetricsBuilder().SampleWith.SlidingWindow().SampleWith.ForwardDecaying().Build(); + metricsBuilder = metrics.Build as DefaultMetricsBuilderFactory; + var reservoir = metricsBuilder?.DefaultSamplingReservoir.Instance(); + + // Assert + reservoir.Should().BeOfType(); + } + + [Fact] + public void Can_set_default_reservoir_to_sliding_window() + { + // Arrange + DefaultMetricsBuilderFactory metricsBuilder; + + // Act + var metrics = new MetricsBuilder().SampleWith.SlidingWindow().Build(); + metricsBuilder = metrics.Build as DefaultMetricsBuilderFactory; + var reservoir = metricsBuilder?.DefaultSamplingReservoir.Instance(); + + // Assert + reservoir.Should().BeOfType(); + } + + [Fact] + public void Default_reservoir_is_forward_decaying() + { + // Arrange + DefaultMetricsBuilderFactory metricsBuilder; + + // Act + var metrics = new MetricsBuilder().Build(); + metricsBuilder = metrics.Build as DefaultMetricsBuilderFactory; + var reservoir = metricsBuilder?.DefaultSamplingReservoir.Instance(); + + // Assert + reservoir.Should().BeOfType(); + } + } +} \ No newline at end of file diff --git a/test/App.Metrics.Facts/Builders/DefaultMetricsBuilderFactoryTests.cs b/test/App.Metrics.Facts/Builders/DefaultMetricsBuilderFactoryTests.cs index 165b793b..88ce444d 100644 --- a/test/App.Metrics.Facts/Builders/DefaultMetricsBuilderFactoryTests.cs +++ b/test/App.Metrics.Facts/Builders/DefaultMetricsBuilderFactoryTests.cs @@ -3,6 +3,8 @@ // using App.Metrics.Internal; +using App.Metrics.ReservoirSampling; +using App.Metrics.ReservoirSampling.ExponentialDecay; using FluentAssertions; using Xunit; @@ -12,7 +14,7 @@ public class DefaultMetricsBuilderFactoryTests { private readonly DefaultMetricsBuilderFactory _factory; - public DefaultMetricsBuilderFactoryTests() { _factory = new DefaultMetricsBuilderFactory(); } + public DefaultMetricsBuilderFactoryTests() { _factory = new DefaultMetricsBuilderFactory(new DefaultSamplingReservoirProvider(() => new DefaultForwardDecayingReservoir())); } [Fact] public void Creates_apdex_builder() diff --git a/test/App.Metrics.Facts/Extensions/AppMetricsOptionExtensionsTests.cs b/test/App.Metrics.Facts/Extensions/AppMetricsOptionExtensionsTests.cs index 8b8061f9..61e363fb 100644 --- a/test/App.Metrics.Facts/Extensions/AppMetricsOptionExtensionsTests.cs +++ b/test/App.Metrics.Facts/Extensions/AppMetricsOptionExtensionsTests.cs @@ -20,7 +20,6 @@ public void Can_set_global_tags_on_metric_options() var expected = new GlobalMetricTags( new Dictionary { - { "host", environmentInfo.HostName }, { "machine_name", environmentInfo.MachineName }, { "app_name", environmentInfo.EntryAssemblyName }, { "app_version", environmentInfo.EntryAssemblyVersion } @@ -30,7 +29,6 @@ public void Can_set_global_tags_on_metric_options() options.WithGlobalTags( (globalTags, envInfo) => { - globalTags.Add("host", envInfo.HostName); globalTags.Add("machine_name", envInfo.MachineName); globalTags.Add("app_name", envInfo.EntryAssemblyName); globalTags.Add("app_version", envInfo.EntryAssemblyVersion); diff --git a/test/App.Metrics.Facts/Fixtures/MetricCoreTestFixture.cs b/test/App.Metrics.Facts/Fixtures/MetricCoreTestFixture.cs index 14d1dcae..4b1623ba 100644 --- a/test/App.Metrics.Facts/Fixtures/MetricCoreTestFixture.cs +++ b/test/App.Metrics.Facts/Fixtures/MetricCoreTestFixture.cs @@ -7,7 +7,8 @@ using App.Metrics.Filtering; using App.Metrics.Internal; using App.Metrics.Registry; -using Microsoft.Extensions.Logging; +using App.Metrics.ReservoirSampling; +using App.Metrics.ReservoirSampling.ExponentialDecay; using Microsoft.Extensions.Options; using Moq; @@ -23,11 +24,11 @@ public MetricCoreTestFixture() .Returns(new MetricsOptions()); Clock = new TestClock(); - Builder = new DefaultMetricsBuilderFactory(); + Builder = new DefaultMetricsBuilderFactory(new DefaultSamplingReservoirProvider(() => new DefaultForwardDecayingReservoir())); IMetricContextRegistry ContextRegistrySetup(string context) => new DefaultMetricContextRegistry(context); - var registry = new DefaultMetricsRegistry(options.Object, Clock, ContextRegistrySetup); + var registry = new DefaultMetricsRegistry(options.Object.Value.DefaultContextLabel, Clock, ContextRegistrySetup); Registry = registry; Providers = new DefaultMetricsProvider(Registry, Builder, Clock); diff --git a/test/App.Metrics.Facts/Infrastructure/EnvironmentInfoEqualityTests.cs b/test/App.Metrics.Facts/Infrastructure/EnvironmentInfoEqualityTests.cs index 3b8cb64e..3401bf5e 100644 --- a/test/App.Metrics.Facts/Infrastructure/EnvironmentInfoEqualityTests.cs +++ b/test/App.Metrics.Facts/Infrastructure/EnvironmentInfoEqualityTests.cs @@ -13,8 +13,8 @@ public class EnvironmentInfoEqualityTests [Fact] public void Different_hashcodes_when_values_differ() { - var env = new EnvironmentInfo("framework", "assembly", "entry", "host", "time", "machine", "OS", "OS version", "x64", "x64", "process", "4"); - var env2 = new EnvironmentInfo("framework", "assembly", "entry", "host", "time", "machine", "OS2", "OS version2", "x64", "x64", "process", "4"); + var env = new EnvironmentInfo("framework", "assembly", "entry", "time", "machine", "OS", "OS version", "x64", "x64", "4"); + var env2 = new EnvironmentInfo("framework", "assembly", "entry", "time", "machine", "OS2", "OS version2", "x64", "x64", "4"); (env.GetHashCode() == env2.GetHashCode()).Should().BeFalse(); } @@ -22,8 +22,8 @@ public void Different_hashcodes_when_values_differ() [Fact] public void Equality_with_equals() { - var env = new EnvironmentInfo("framework", "assembly", "entry", "host", "time", "machine", "OS", "OS version", "x64", "x64", "process", "4"); - var other = new EnvironmentInfo("framework", "assembly", "entry", "host", "time", "machine", "OS", "OS version", "x64", "x64", "process", "4"); + var env = new EnvironmentInfo("framework", "assembly", "entry", "time", "machine", "OS", "OS version", "x64", "x64", "4"); + var other = new EnvironmentInfo("framework", "assembly", "entry", "time", "machine", "OS", "OS version", "x64", "x64", "4"); env.Equals(other).Should().Be(true); } @@ -31,7 +31,7 @@ public void Equality_with_equals() [Fact] public void Equality_with_equals_false_when_same_object() { - var env = new EnvironmentInfo("framework", "assembly", "entry", "host", "time", "machine", "OS", "OS version", "x64", "x64", "process", "4"); + var env = new EnvironmentInfo("framework", "assembly", "entry", "time", "machine", "OS", "OS version", "x64", "x64", "4"); object other = env; @@ -41,8 +41,8 @@ public void Equality_with_equals_false_when_same_object() [Fact] public void Equality_with_equals_operator() { - var env = new EnvironmentInfo("framework", "assembly", "entry", "host", "time", "machine", "OS", "OS version", "x64", "x64", "process", "4"); - var other = new EnvironmentInfo("framework", "assembly", "entry", "host", "time", "machine", "OS", "OS version", "x64", "x64", "process", "4"); + var env = new EnvironmentInfo("framework", "assembly", "entry", "time", "machine", "OS", "OS version", "x64", "x64", "4"); + var other = new EnvironmentInfo("framework", "assembly", "entry", "time", "machine", "OS", "OS version", "x64", "x64", "4"); (env == other).Should().Be(true); } @@ -50,8 +50,8 @@ public void Equality_with_equals_operator() [Fact] public void Equality_with_not_equals_operator() { - var env = new EnvironmentInfo("framework", "assembly", "entry", "host", "time", "machine", "OS", "OS version", "x64", "x64", "process", "4"); - var other = new EnvironmentInfo("framework", "assembly2", "entry", "host", "time", "machine", "OS", "OS version", "x64", "x64", "process", "4"); + var env = new EnvironmentInfo("framework", "assembly", "entry", "time", "machine", "OS", "OS version", "x64", "x64", "4"); + var other = new EnvironmentInfo("framework", "assembly2", "entry", "time", "machine", "OS", "OS version", "x64", "x64", "4"); (env != other).Should().Be(true); } @@ -59,8 +59,8 @@ public void Equality_with_not_equals_operator() [Fact] public void Same_hashcodes_when_values_match() { - var env = new EnvironmentInfo("framework", "assembly", "entry", "host", "time", "machine", "OS", "OS version", "x64", "x64", "process", "4"); - var env2 = new EnvironmentInfo("framework", "assembly", "entry", "host", "time", "machine", "OS", "OS version", "x64", "x64", "process", "4"); + var env = new EnvironmentInfo("framework", "assembly", "entry", "time", "machine", "OS", "OS version", "x64", "x64", "4"); + var env2 = new EnvironmentInfo("framework", "assembly", "entry", "time", "machine", "OS", "OS version", "x64", "x64", "4"); (env.GetHashCode() == env2.GetHashCode()).Should().BeTrue(); } diff --git a/test/App.Metrics.Facts/Options/KeyValuePairMetricsOptionsTests.cs b/test/App.Metrics.Facts/Options/KeyValuePairMetricsOptionsTests.cs new file mode 100644 index 00000000..bd72c86f --- /dev/null +++ b/test/App.Metrics.Facts/Options/KeyValuePairMetricsOptionsTests.cs @@ -0,0 +1,117 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System; +using System.Collections.Generic; +using System.Linq; +using FluentAssertions; +using Xunit; + +namespace App.Metrics.Facts.Options +{ + public class KeyValuePairMetricsOptionsTests + { + [Fact] + public void Can_load_options_from_key_values() + { + // Arrange + var keyValuePairs = new Dictionary + { + { "AddDefaultGlobalTags", "false" }, + { "DefaultContextLabel", "Testing" }, + { "GlobalTags", "tag1=value1, tag2=value2" }, + { "MetricsEnabled", "false" } + }; + + // Act + var options = new KeyValuePairMetricsOptions(keyValuePairs).AsOptions(); + + // Assert + options.AddDefaultGlobalTags.Should().BeFalse(); + options.DefaultContextLabel.Should().Be("Testing"); + options.GlobalTags.Count.Should().Be(2); + options.GlobalTags.First().Key.Should().Be("tag1"); + options.GlobalTags.First().Value.Should().Be("value1"); + options.GlobalTags.Skip(1).First().Key.Should().Be("tag2"); + options.GlobalTags.Skip(1).First().Value.Should().Be("value2"); + options.MetricsEnabled.Should().BeFalse(); + } + + [Fact] + public void Key_value_pairs_cannot_be_null() + { + // Arrange + // Act + Action action = () => + { + var options = new KeyValuePairMetricsOptions(null); + }; + + // Assert + action.ShouldThrow(); + } + + [Fact] + public void Add_default_global_tags_should_be_bool() + { + // Arrange + // Act + Action action = () => + { + var keyValuePairs = new Dictionary + { + { "AddDefaultGlobalTags", "not_a_bool" } + }; + + // Act + var options = new KeyValuePairMetricsOptions(keyValuePairs).AsOptions(); + }; + + // Assert + action.ShouldThrow(); + } + + [Fact] + public void Metrics_enabled_should_be_bool() + { + // Arrange + // Act + Action action = () => + { + var keyValuePairs = new Dictionary + { + { "MetricsEnabled", "not_a_bool" } + }; + + // Act + var options = new KeyValuePairMetricsOptions(keyValuePairs).AsOptions(); + }; + + // Assert + action.ShouldThrow(); + } + + [Theory] + [InlineData("invalidseperator|value1, tag2=value2")] + [InlineData("no_comma")] + public void Global_tags_should_be_formatted_correctly(string tags) + { + // Arrange + // Act + Action action = () => + { + var keyValuePairs = new Dictionary + { + { "GlobalTags", tags } + }; + + // Act + var options = new KeyValuePairMetricsOptions(keyValuePairs).AsOptions(); + }; + + // Assert + action.ShouldThrow(); + } + } +} diff --git a/test/App.Metrics.FactsCommon/App.Metrics.FactsCommon.csproj b/test/App.Metrics.FactsCommon/App.Metrics.FactsCommon.csproj index 29299dcb..62b40bc7 100644 --- a/test/App.Metrics.FactsCommon/App.Metrics.FactsCommon.csproj +++ b/test/App.Metrics.FactsCommon/App.Metrics.FactsCommon.csproj @@ -17,8 +17,6 @@ - - diff --git a/test/App.Metrics.FactsCommon/Fixtures/MetricsFixture.cs b/test/App.Metrics.FactsCommon/Fixtures/MetricsFixture.cs index c9cdadff..40980255 100644 --- a/test/App.Metrics.FactsCommon/Fixtures/MetricsFixture.cs +++ b/test/App.Metrics.FactsCommon/Fixtures/MetricsFixture.cs @@ -7,9 +7,8 @@ using App.Metrics.Filters; using App.Metrics.Internal; using App.Metrics.Registry; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Moq; +using App.Metrics.ReservoirSampling; +using App.Metrics.ReservoirSampling.ExponentialDecay; namespace App.Metrics.FactsCommon.Fixtures { @@ -18,15 +17,12 @@ public class MetricsFixture : IDisposable public MetricsFixture() { Clock = new TestClock(); - var options = new Mock>(); - options - .SetupGet(o => o.Value) - .Returns(new MetricsOptions()); + var options = new MetricsOptions(); IMetricContextRegistry NewContextRegistry(string name) => new DefaultMetricContextRegistry(name); - var registry = new DefaultMetricsRegistry(options.Object, Clock, NewContextRegistry); - var metricBuilderFactory = new DefaultMetricsBuilderFactory(); + var registry = new DefaultMetricsRegistry(options.DefaultContextLabel, Clock, NewContextRegistry); + var metricBuilderFactory = new DefaultMetricsBuilderFactory(new DefaultSamplingReservoirProvider(() => new DefaultForwardDecayingReservoir())); var filter = new DefaultMetricsFilter(); var dataManager = new DefaultMetricValuesProvider(filter, registry); var metricsManagerFactory = new DefaultMeasureMetricsProvider(registry, metricBuilderFactory, Clock); diff --git a/test/App.Metrics.Formatters.Ascii.Facts/App.Metrics.Formatters.Ascii.Facts.csproj b/test/App.Metrics.Formatters.Ascii.Facts/App.Metrics.Formatters.Ascii.Facts.csproj index 9361ae2a..91a2c334 100644 --- a/test/App.Metrics.Formatters.Ascii.Facts/App.Metrics.Formatters.Ascii.Facts.csproj +++ b/test/App.Metrics.Formatters.Ascii.Facts/App.Metrics.Formatters.Ascii.Facts.csproj @@ -13,8 +13,6 @@ - - diff --git a/test/App.Metrics.Formatters.Ascii.Facts/Builder/MetricsTextEnvOutputFormattingBuilderTests.cs b/test/App.Metrics.Formatters.Ascii.Facts/Builder/MetricsTextEnvOutputFormattingBuilderTests.cs new file mode 100644 index 00000000..e415d469 --- /dev/null +++ b/test/App.Metrics.Formatters.Ascii.Facts/Builder/MetricsTextEnvOutputFormattingBuilderTests.cs @@ -0,0 +1,28 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System.Linq; +using FluentAssertions; +using Xunit; + +namespace App.Metrics.Formatters.Ascii.Facts.Builder +{ + public class MetricsTextEnvOutputFormattingBuilderTests + { + [Fact] + public void Can_set_env_plain_text_output_formatting() + { + // Arrange + var builder = new MetricsBuilder().OutputEnvInfo.AsPlainText(); + + // Act + var metrics = builder.Build(); + + // Assert + metrics.DefaultOutputEnvFormatter.Should().BeOfType(); + metrics.OutputEnvFormatters.Count.Should().Be(1); + metrics.OutputEnvFormatters.First().Should().BeOfType(); + } + } +} \ No newline at end of file diff --git a/test/App.Metrics.Formatters.Ascii.Facts/Builder/MetricsTextOutputFormattingBuilderTests.cs b/test/App.Metrics.Formatters.Ascii.Facts/Builder/MetricsTextOutputFormattingBuilderTests.cs new file mode 100644 index 00000000..6242eb01 --- /dev/null +++ b/test/App.Metrics.Formatters.Ascii.Facts/Builder/MetricsTextOutputFormattingBuilderTests.cs @@ -0,0 +1,28 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System.Linq; +using FluentAssertions; +using Xunit; + +namespace App.Metrics.Formatters.Ascii.Facts.Builder +{ + public class MetricsTextOutputFormattingBuilderTests + { + [Fact] + public void Can_set_metrics_plain_text_output_formatting() + { + // Arrange + var builder = new MetricsBuilder().OutputMetrics.AsPlainText(); + + // Act + var metrics = builder.Build(); + + // Assert + metrics.DefaultOutputMetricsFormatter.Should().BeOfType(); + metrics.OutputMetricsFormatters.Count.Should().Be(1); + metrics.OutputMetricsFormatters.First().Should().BeOfType(); + } + } +} \ No newline at end of file diff --git a/test/App.Metrics.Formatters.Json.Facts/App.Metrics.Formatters.Json.Facts.csproj b/test/App.Metrics.Formatters.Json.Facts/App.Metrics.Formatters.Json.Facts.csproj index 541cf5a2..8a9f3862 100644 --- a/test/App.Metrics.Formatters.Json.Facts/App.Metrics.Formatters.Json.Facts.csproj +++ b/test/App.Metrics.Formatters.Json.Facts/App.Metrics.Formatters.Json.Facts.csproj @@ -25,8 +25,6 @@ - - diff --git a/test/App.Metrics.Formatters.Json.Facts/Builder/MetricsJsonEnvOutputFormattingBuilderTests.cs b/test/App.Metrics.Formatters.Json.Facts/Builder/MetricsJsonEnvOutputFormattingBuilderTests.cs new file mode 100644 index 00000000..20da1fc9 --- /dev/null +++ b/test/App.Metrics.Formatters.Json.Facts/Builder/MetricsJsonEnvOutputFormattingBuilderTests.cs @@ -0,0 +1,28 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System.Linq; +using FluentAssertions; +using Xunit; + +namespace App.Metrics.Formatters.Json.Facts.Builder +{ + public class MetricsJsonEnvOutputFormattingBuilderTests + { + [Fact] + public void Can_set_env_plain_text_output_formatting() + { + // Arrange + var builder = new MetricsBuilder().OutputEnvInfo.AsJson(); + + // Act + var metrics = builder.Build(); + + // Assert + metrics.DefaultOutputEnvFormatter.Should().BeOfType(); + metrics.OutputEnvFormatters.Count.Should().Be(1); + metrics.OutputEnvFormatters.First().Should().BeOfType(); + } + } +} \ No newline at end of file diff --git a/test/App.Metrics.Formatters.Json.Facts/Builder/MetricsJsonOutputFormattingBuilderTests.cs b/test/App.Metrics.Formatters.Json.Facts/Builder/MetricsJsonOutputFormattingBuilderTests.cs new file mode 100644 index 00000000..65019332 --- /dev/null +++ b/test/App.Metrics.Formatters.Json.Facts/Builder/MetricsJsonOutputFormattingBuilderTests.cs @@ -0,0 +1,28 @@ +// +// Copyright (c) Allan Hardy. All rights reserved. +// + +using System.Linq; +using FluentAssertions; +using Xunit; + +namespace App.Metrics.Formatters.Json.Facts.Builder +{ + public class MetricsJsonOutputFormattingBuilderTests + { + [Fact] + public void Can_set_metrics_json_output_formatting() + { + // Arrange + var builder = new MetricsBuilder().OutputMetrics.AsJson(); + + // Act + var metrics = builder.Build(); + + // Assert + metrics.DefaultOutputMetricsFormatter.Should().BeOfType(); + metrics.OutputMetricsFormatters.Count.Should().Be(1); + metrics.OutputMetricsFormatters.First().Should().BeOfType(); + } + } +} \ No newline at end of file diff --git a/test/App.Metrics.Formatters.Json.Facts/JsonFiles/env.json b/test/App.Metrics.Formatters.Json.Facts/JsonFiles/env.json index 5e0f1b9c..15f10894 100644 --- a/test/App.Metrics.Formatters.Json.Facts/JsonFiles/env.json +++ b/test/App.Metrics.Formatters.Json.Facts/JsonFiles/env.json @@ -11,10 +11,6 @@ "name": "ProcessArchitecture", "value": "process_arch" }, - { - "name": "ProcessName", - "value": "process_name" - }, { "name": "OperatingSystemArchitecture", "value": "os_arch" @@ -31,10 +27,6 @@ "name": "CPUCount", "value": "8" }, - { - "name": "HostName", - "value": "host_name" - }, { "name": "LocalTime", "value": "localtime" diff --git a/test/App.Metrics.Formatters.Json.Facts/TestFixtures/MetricProviderTestFixture.cs b/test/App.Metrics.Formatters.Json.Facts/TestFixtures/MetricProviderTestFixture.cs index 762abab4..9f8b84e0 100644 --- a/test/App.Metrics.Formatters.Json.Facts/TestFixtures/MetricProviderTestFixture.cs +++ b/test/App.Metrics.Formatters.Json.Facts/TestFixtures/MetricProviderTestFixture.cs @@ -64,14 +64,12 @@ public MetricProviderTestFixture() "framework", "assembly_name", "assembly_version", - "host_name", "localtime", "machine_name", "os", "os_version", "os_arch", "process_arch", - "process_name", "8"); public string GaugeNameDefault { get; } = "test_gauge";