diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bb9e809..893aaca3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.3.27 (01-10-2021): + +- Added `DiagnosticMetricsEnabled` settings +- Fixed #60 + ## 0.3.26 (16-09-2021): Add possibility to target setup of host metrics. diff --git a/Vostok.Hosting.Tests/VostokHost_Tests_Dispose.cs b/Vostok.Hosting.Tests/VostokHost_Tests_Dispose.cs index 8e74c157..bb0c8f66 100644 --- a/Vostok.Hosting.Tests/VostokHost_Tests_Dispose.cs +++ b/Vostok.Hosting.Tests/VostokHost_Tests_Dispose.cs @@ -51,13 +51,11 @@ public void Should_not_block_on_dispose_longer_than_shutdown_timeout_allows() var host = new VostokHost(new TestHostSettings(app, SetupEnvironment)); - host.Start(); - var watch = Stopwatch.StartNew(); - host.Stop().State.Should().Be(VostokApplicationState.Exited); + host.Run().State.Should().Be(VostokApplicationState.Exited); - watch.Elapsed.Should().BeLessThan(2.Seconds()); + watch.Elapsed.Should().BeLessThan(5.Seconds()); } private static void SetupEnvironment(IVostokHostingEnvironmentBuilder builder) diff --git a/Vostok.Hosting.Tests/VostokHostingEnvironmentFactory_Tests.cs b/Vostok.Hosting.Tests/VostokHostingEnvironmentFactory_Tests.cs index 5f03874f..8ec834fa 100644 --- a/Vostok.Hosting.Tests/VostokHostingEnvironmentFactory_Tests.cs +++ b/Vostok.Hosting.Tests/VostokHostingEnvironmentFactory_Tests.cs @@ -10,6 +10,7 @@ using Vostok.Hosting.Components.Shutdown; using Vostok.Hosting.Components.ZooKeeper; using Vostok.Hosting.Setup; +using Vostok.Metrics; using Vostok.Metrics.System.Gc; using Vostok.Metrics.System.Process; @@ -30,7 +31,7 @@ public void TestSetup() public void Should_produce_an_environment_with_linked_cancellation_tokens() { var environment = VostokHostingEnvironmentFactory.Create(Setup); - + shutdown.Cancel(); Action assertion = () => environment.ShutdownToken.IsCancellationRequested.Should().BeTrue(); @@ -55,20 +56,21 @@ public void Should_produce_an_environment_with_ticking_shutdown_budget_upon_canc var immediatelyAfter = environment.ShutdownTimeout; - Thread.Sleep(100); - - var awhileAfter = environment.ShutdownTimeout; - - awhileAfter.Should().BeLessThan(immediatelyAfter); + new Action(() => + { + environment.ShutdownTimeout.Should().BeLessThan(immediatelyAfter); + }).ShouldPassIn(5.Seconds()); } [Test] public void Should_substract_beacon_shutdown_timeout_from_total() { - var environment = VostokHostingEnvironmentFactory.Create(SetupWithServiceDiscovery, new VostokHostingEnvironmentFactorySettings - { - BeaconShutdownTimeout = 3.Seconds() - }); + var environment = VostokHostingEnvironmentFactory.Create( + SetupWithServiceDiscovery, + new VostokHostingEnvironmentFactorySettings + { + BeaconShutdownTimeout = 3.Seconds() + }); environment.ShutdownTimeout.Should().Be(27.Seconds()); } @@ -76,10 +78,12 @@ public void Should_substract_beacon_shutdown_timeout_from_total() [Test] public void Should_not_substract_beacon_shutdown_timeout_from_total_if_there_is_no_real_beacon() { - var environment = VostokHostingEnvironmentFactory.Create(Setup, new VostokHostingEnvironmentFactorySettings - { - BeaconShutdownTimeout = 3.Seconds() - }); + var environment = VostokHostingEnvironmentFactory.Create( + Setup, + new VostokHostingEnvironmentFactorySettings + { + BeaconShutdownTimeout = 3.Seconds() + }); environment.ShutdownTimeout.Should().Be(30.Seconds()); } @@ -87,10 +91,12 @@ public void Should_not_substract_beacon_shutdown_timeout_from_total_if_there_is_ [Test] public void Should_wait_after_beacon_shutdown_if_instructed_to_do_so() { - var environment = VostokHostingEnvironmentFactory.Create(SetupWithServiceDiscovery, new VostokHostingEnvironmentFactorySettings - { - BeaconShutdownTimeout = 1.Seconds() - }); + var environment = VostokHostingEnvironmentFactory.Create( + SetupWithServiceDiscovery, + new VostokHostingEnvironmentFactorySettings + { + BeaconShutdownTimeout = 1.Seconds() + }); var watch = Stopwatch.StartNew(); @@ -104,11 +110,13 @@ public void Should_wait_after_beacon_shutdown_if_instructed_to_do_so() [Test] public void Should_not_wait_after_beacon_shutdown_if_disabled() { - var environment = VostokHostingEnvironmentFactory.Create(SetupWithServiceDiscovery, new VostokHostingEnvironmentFactorySettings - { - BeaconShutdownTimeout = 2.Seconds(), - BeaconShutdownWaitEnabled = false - }); + var environment = VostokHostingEnvironmentFactory.Create( + SetupWithServiceDiscovery, + new VostokHostingEnvironmentFactorySettings + { + BeaconShutdownTimeout = 2.Seconds(), + BeaconShutdownWaitEnabled = false + }); var watch = Stopwatch.StartNew(); @@ -142,6 +150,59 @@ public void Should_provide_system_metrics_extensions() environment.HostExtensions.TryGet(out _).Should().BeTrue(); } + [Test] + public void Should_provide_dev_null_metric_context_when_diagnostic_metrics_disabled_and_no_senders() + { + var environment = VostokHostingEnvironmentFactory.Create(Setup, new VostokHostingEnvironmentFactorySettings + { + DiagnosticMetricsEnabled = false + }); + + environment.Metrics.Root.Should().BeOfType(); + } + + [Test] + public void Should_provide_dev_null_metric_context_when_no_metric_event_senders_built() + { + var environment = VostokHostingEnvironmentFactory.Create(SetupForDevNullMetricContext, new VostokHostingEnvironmentFactorySettings()); + + environment.Metrics.Root.Should().BeOfType(); + + void SetupForDevNullMetricContext(IVostokHostingEnvironmentBuilder builder) + { + Setup(builder); + builder.SetupDiagnostics(x => x.CustomizeInfo(s => s.AddApplicationMetricsInfo = false)); // disable ApplicationMetricsProvider metrics sender + } + } + + [Test] + public void Should_provide_not_dev_null_metric_context_when_metric_event_senders_built() + { + var environment = VostokHostingEnvironmentFactory.Create(SetupForDevNullMetricContext, new VostokHostingEnvironmentFactorySettings()); + + environment.Metrics.Root.Should().BeOfType(); + + void SetupForDevNullMetricContext(IVostokHostingEnvironmentBuilder builder) + { + Setup(builder); + builder.SetupDiagnostics(x => x.CustomizeInfo(s => s.AddApplicationMetricsInfo = true)); // enable ApplicationMetricsProvider metrics sender + } + } + + [Test, Explicit] + public void Should_not_leak() + { + for (int i = 0; i < 100; i++) + { + var environment = VostokHostingEnvironmentFactory.Create(Setup, + new VostokHostingEnvironmentFactorySettings + { + ConfigureStaticProviders = false + }); + (environment as IDisposable)?.Dispose(); + } + } + private void Setup(IVostokHostingEnvironmentBuilder builder) { builder.DisableClusterConfig(); @@ -178,4 +239,4 @@ private void SetupCommons(IVostokHostingEnvironmentBuilder builder) builder.SetupLog(log => log.SetupConsoleLog()); } } -} +} \ No newline at end of file diff --git a/Vostok.Hosting/Components/Environment/EnvironmentBuilder.cs b/Vostok.Hosting/Components/Environment/EnvironmentBuilder.cs index 35693898..ecdad9ef 100644 --- a/Vostok.Hosting/Components/Environment/EnvironmentBuilder.cs +++ b/Vostok.Hosting/Components/Environment/EnvironmentBuilder.cs @@ -141,7 +141,7 @@ private VostokHostingEnvironment BuildInner(BuildContext context) context.SecretConfigurationProvider) = configurationBuilder.Build(context); } - if (settings.ConfigureStaticProviders && context.ConfigurationProvider is ConfigurationProvider configProvider) + if (settings.ConfigureStaticProviders && context.ConfigurationProvider is {} configProvider) ConfigurationProvider.TrySetDefault(configProvider); context.EnvironmentSetupContext = new EnvironmentSetupContext( @@ -188,7 +188,7 @@ private VostokHostingEnvironment BuildInner(BuildContext context) context.SubstituteTracer(tracerBuilder.Build(context)); - if (diagnosticsBuilder.Builder.NeedsApplicationMetricsProvider) + if (settings.DiagnosticMetricsEnabled && diagnosticsBuilder.GetIntermediateBuilder(context).NeedsApplicationMetricsProvider) { context.MetricsInfoProvider = new ApplicationMetricsProvider(); metricsBuilder.AddCustomization(metrics => metrics.AddMetricEventSender(context.MetricsInfoProvider)); @@ -201,7 +201,8 @@ private VostokHostingEnvironment BuildInner(BuildContext context) if (settings.SendAnnotations) AnnotationsHelper.ReportLaunching(context.ApplicationIdentity, context.Metrics.Instance); - context.RegisterDisposable(HerculesSinkMetrics.Measure(context.HerculesSink, context.Metrics, context.Log)); + if (settings.DiagnosticMetricsEnabled) + context.RegisterDisposable(HerculesSinkMetrics.Measure(context.HerculesSink, context.Metrics, context.Log)); if (settings.ConfigureStaticProviders) FlowingContext.Configuration.ErrorCallback = (errorMessage, error) => context.Log.ForContext(typeof(FlowingContext)).Error(error, errorMessage); @@ -218,7 +219,9 @@ private VostokHostingEnvironment BuildInner(BuildContext context) context.ConfigurationSource.SwitchTo(src => src.Substitute(configSubstitutions)); context.SecretConfigurationSource.SwitchTo(src => src.Substitute(configSubstitutions)); - context.DiagnosticsHub = diagnosticsBuilder.Build(context); + context.DiagnosticsHub = settings.DiagnosticMetricsEnabled + ? diagnosticsBuilder.Build(context) + : new DiagnosticsHub(new DiagnosticInfo(), new HealthTracker(TimeSpan.MaxValue, context.Log)); var (hostingShutdown, applicationShutdown) = ShutdownFactory.Create( context.ServiceBeacon, @@ -261,7 +264,8 @@ private VostokHostingEnvironment BuildInner(BuildContext context) hostExtensionsBuilder.Build(context, vostokHostingEnvironment); - systemMetricsBuilder.Build(context, vostokHostingEnvironment); + if (settings.DiagnosticMetricsEnabled) + systemMetricsBuilder.Build(context, vostokHostingEnvironment); if (!hasLogs) { @@ -270,14 +274,17 @@ private VostokHostingEnvironment BuildInner(BuildContext context) context.Log = context.Logs.BuildCompositeLog(out _); } - context.RegisterDisposable(LogLevelMetrics.Measure(context.Logs.LogEventLevelCounterFactory.CreateCounter(), context.Metrics)); + if (settings.DiagnosticMetricsEnabled) + context.RegisterDisposable(LogLevelMetrics.Measure(context.Logs.LogEventLevelCounterFactory.CreateCounter(), context.Metrics)); if (settings.ConfigureStaticProviders) StaticProvidersHelper.Configure(vostokHostingEnvironment); - context.DiagnosticsHub.HealthTracker.LaunchPeriodicalChecks(vostokHostingEnvironment.ShutdownToken); + if (settings.DiagnosticMetricsEnabled) + context.DiagnosticsHub.HealthTracker.LaunchPeriodicalChecks(vostokHostingEnvironment.ShutdownToken); - context.RegisterDisposable(HealthCheckMetrics.Measure(context.DiagnosticsHub.HealthTracker, context.Metrics)); + if (settings.DiagnosticMetricsEnabled) + context.RegisterDisposable(HealthCheckMetrics.Measure(context.DiagnosticsHub.HealthTracker, context.Metrics)); return vostokHostingEnvironment; } diff --git a/Vostok.Hosting/Helpers/CustomizableBuilder.cs b/Vostok.Hosting/Helpers/CustomizableBuilder.cs index 7c803b2d..7ad4ea06 100644 --- a/Vostok.Hosting/Helpers/CustomizableBuilder.cs +++ b/Vostok.Hosting/Helpers/CustomizableBuilder.cs @@ -10,7 +10,7 @@ internal class CustomizableBuilder { private readonly TBuilder builder; private readonly Customization builderCustomization; - + private volatile IVostokHostingEnvironmentSetupContext environmentSetupContext; private volatile IVostokConfigurationSetupContext configurationSetupContext; @@ -20,8 +20,6 @@ public CustomizableBuilder(TBuilder builder) builderCustomization = new Customization(); } - public TBuilder Builder => builder; - public void AddCustomization(Action setup) => builderCustomization.AddCustomization(setup); @@ -40,5 +38,21 @@ public TResult Build(BuildContext context) return builder.Build(context); } + + public TBuilder GetIntermediateBuilder(BuildContext context) + { + try + { + environmentSetupContext = context.EnvironmentSetupContext; + configurationSetupContext = context.ConfigurationSetupContext; + + return builderCustomization.Customize(builder); + } + finally + { + environmentSetupContext = null; + configurationSetupContext = null; + } + } } } \ No newline at end of file diff --git a/Vostok.Hosting/MultiHost/VostokMultiHost.cs b/Vostok.Hosting/MultiHost/VostokMultiHost.cs index c8f606b7..addb0ff3 100644 --- a/Vostok.Hosting/MultiHost/VostokMultiHost.cs +++ b/Vostok.Hosting/MultiHost/VostokMultiHost.cs @@ -247,7 +247,8 @@ private VostokHostingEnvironment SetupEnvironment() { var environmentFactorySettings = new VostokHostingEnvironmentFactorySettings { - ConfigureStaticProviders = settings.ConfigureStaticProviders + ConfigureStaticProviders = settings.ConfigureStaticProviders, + DiagnosticMetricsEnabled = settings.DiagnosticMetricsEnabled }; return EnvironmentBuilder.Build( diff --git a/Vostok.Hosting/MultiHost/VostokMultiHostApplication.cs b/Vostok.Hosting/MultiHost/VostokMultiHostApplication.cs index 9d9c82c3..b074d1be 100644 --- a/Vostok.Hosting/MultiHost/VostokMultiHostApplication.cs +++ b/Vostok.Hosting/MultiHost/VostokMultiHostApplication.cs @@ -91,6 +91,7 @@ private void CreateVostokHost(bool throwsException = true) ConfigureStaticProviders = false, WarmupConfiguration = false, WarmupZooKeeper = false, + DiagnosticMetricsEnabled = false }; vostokHost = new VostokHost(vostokHostSettings); diff --git a/Vostok.Hosting/MultiHost/VostokMultiHostSettings.cs b/Vostok.Hosting/MultiHost/VostokMultiHostSettings.cs index 27f41d69..b74a19fd 100644 --- a/Vostok.Hosting/MultiHost/VostokMultiHostSettings.cs +++ b/Vostok.Hosting/MultiHost/VostokMultiHostSettings.cs @@ -30,5 +30,8 @@ public VostokMultiHostSettings(VostokHostingEnvironmentSetup builder) /// public int ThreadPoolTuningMultiplier { get; set; } = ThreadPoolConstants.DefaultThreadPoolMultiplier; + + /// + public bool DiagnosticMetricsEnabled { get; set; } } } \ No newline at end of file diff --git a/Vostok.Hosting/Vostok.Hosting.csproj b/Vostok.Hosting/Vostok.Hosting.csproj index 835ff9f0..60722338 100644 --- a/Vostok.Hosting/Vostok.Hosting.csproj +++ b/Vostok.Hosting/Vostok.Hosting.csproj @@ -8,7 +8,7 @@ latest - 0.3.27 + 0.3.28 Vostok.Hosting diff --git a/Vostok.Hosting/VostokHost.cs b/Vostok.Hosting/VostokHost.cs index b1f925bb..6f2b87c4 100644 --- a/Vostok.Hosting/VostokHost.cs +++ b/Vostok.Hosting/VostokHost.cs @@ -208,7 +208,8 @@ private VostokApplicationRunResult BuildEnvironment() ConfigureStaticProviders = settings.ConfigureStaticProviders, BeaconShutdownTimeout = settings.BeaconShutdownTimeout, BeaconShutdownWaitEnabled = settings.BeaconShutdownWaitEnabled, - SendAnnotations = settings.SendAnnotations + SendAnnotations = settings.SendAnnotations, + DiagnosticMetricsEnabled = settings.DiagnosticMetricsEnabled }; environment = EnvironmentBuilder.Build(SetupEnvironment, environmentFactorySettings); diff --git a/Vostok.Hosting/VostokHostSettings.cs b/Vostok.Hosting/VostokHostSettings.cs index b2e60f1d..f0a7e848 100644 --- a/Vostok.Hosting/VostokHostSettings.cs +++ b/Vostok.Hosting/VostokHostSettings.cs @@ -67,6 +67,16 @@ public VostokHostSettings([NotNull] IVostokApplication application, [NotNull] Vo /// If set to true, sends annotations with application lifecycle events (launching, initialized, stopping). /// public bool SendAnnotations { get; set; } = true; + + /// + /// If set to false, forcibly disables: + /// + /// All diagnostic metrics + /// All system metrics + /// All health checks + /// + /// + public bool DiagnosticMetricsEnabled { get; set; } = true; /// /// If enabled, will wait for start. diff --git a/Vostok.Hosting/VostokHostingEnvironmentFactorySettings.cs b/Vostok.Hosting/VostokHostingEnvironmentFactorySettings.cs index 0c9ce598..d06dc955 100644 --- a/Vostok.Hosting/VostokHostingEnvironmentFactorySettings.cs +++ b/Vostok.Hosting/VostokHostingEnvironmentFactorySettings.cs @@ -22,5 +22,8 @@ public class VostokHostingEnvironmentFactorySettings /// public bool SendAnnotations { get; set; } = true; + + /// + public bool DiagnosticMetricsEnabled { get; set; } = true; } }